diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 11:20:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 11:20:34 -0400 |
commit | 9779a8325a9bbf4ccd3853e0e4064984cf9da9c9 (patch) | |
tree | 7814d54c7554210ee03d0dbecc546cc2e8a876ec | |
parent | 309e1e4240636f3a9704d77a164a08e1f5a81fea (diff) | |
parent | 61e0e79ee3c609eb34edf2fe023708cba6a79b1f (diff) |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb
* 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb: (47 commits)
uwb: wrong sizeof argument in mac address compare
uwb: don't use printk_ratelimit() so often
uwb: use kcalloc where appropriate
uwb: use time_after() when purging stale beacons
uwb: add credits for the original developers of the UWB/WUSB/WLP subsystems
uwb: add entries in the MAINTAINERS file
uwb: depend on EXPERIMENTAL
wusb: wusb-cbaf (CBA driver) sysfs ABI simplification
uwb: document UWB and WUSB sysfs files
uwb: add symlinks in sysfs between radio controllers and PALs
uwb: dont tranmit identification IEs
uwb: i1480/GUWA100U: fix firmware download issues
uwb: i1480: remove MAC/PHY information checking function
uwb: add Intel i1480 HWA to the UWB RC quirk table
uwb: disable command/event filtering for D-Link DUB-1210
uwb: initialize the debug sub-system
uwb: Fix handling IEs with empty IE data in uwb_est_get_size()
wusb: fix bmRequestType for Abort RPipe request
wusb: fix error path for wusb_set_dev_addr()
wusb: add HWA host controller driver
...
110 files changed, 35819 insertions, 0 deletions
@@ -598,6 +598,11 @@ S: Tamsui town, Taipei county, | |||
598 | S: Taiwan 251 | 598 | S: Taiwan 251 |
599 | S: Republic of China | 599 | S: Republic of China |
600 | 600 | ||
601 | N: Reinette Chatre | ||
602 | E: reinette.chatre@intel.com | ||
603 | D: WiMedia Link Protocol implementation | ||
604 | D: UWB stack bits and pieces | ||
605 | |||
601 | N: Michael Elizabeth Chastain | 606 | N: Michael Elizabeth Chastain |
602 | E: mec@shout.net | 607 | E: mec@shout.net |
603 | D: Configure, Menuconfig, xconfig | 608 | D: Configure, Menuconfig, xconfig |
@@ -2695,6 +2700,12 @@ S: Demonstratsii 8-382 | |||
2695 | S: Tula 300000 | 2700 | S: Tula 300000 |
2696 | S: Russia | 2701 | S: Russia |
2697 | 2702 | ||
2703 | N: Inaky Perez-Gonzalez | ||
2704 | E: inaky.perez-gonzalez@intel.com | ||
2705 | D: UWB stack, HWA-RC driver and HWA-HC drivers | ||
2706 | D: Wireless USB additions to the USB stack | ||
2707 | D: WiMedia Link Protocol bits and pieces | ||
2708 | |||
2698 | N: Gordon Peters | 2709 | N: Gordon Peters |
2699 | E: GordPeters@smarttech.com | 2710 | E: GordPeters@smarttech.com |
2700 | D: Isochronous receive for IEEE 1394 driver (OHCI module). | 2711 | D: Isochronous receive for IEEE 1394 driver (OHCI module). |
diff --git a/Documentation/ABI/testing/sysfs-bus-umc b/Documentation/ABI/testing/sysfs-bus-umc new file mode 100644 index 000000000000..948fec412446 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-umc | |||
@@ -0,0 +1,28 @@ | |||
1 | What: /sys/bus/umc/ | ||
2 | Date: July 2008 | ||
3 | KernelVersion: 2.6.27 | ||
4 | Contact: David Vrabel <david.vrabel@csr.com> | ||
5 | Description: | ||
6 | The Wireless Host Controller Interface (WHCI) | ||
7 | specification describes a PCI-based device with | ||
8 | multiple capabilities; the UWB Multi-interface | ||
9 | Controller (UMC). | ||
10 | |||
11 | The umc bus presents each of the individual | ||
12 | capabilties as a device. | ||
13 | |||
14 | What: /sys/bus/umc/devices/.../capability_id | ||
15 | Date: July 2008 | ||
16 | KernelVersion: 2.6.27 | ||
17 | Contact: David Vrabel <david.vrabel@csr.com> | ||
18 | Description: | ||
19 | The ID of this capability, with 0 being the radio | ||
20 | controller capability. | ||
21 | |||
22 | What: /sys/bus/umc/devices/.../version | ||
23 | Date: July 2008 | ||
24 | KernelVersion: 2.6.27 | ||
25 | Contact: David Vrabel <david.vrabel@csr.com> | ||
26 | Description: | ||
27 | The specification version this capability's hardware | ||
28 | interface complies with. | ||
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index df6c8a0159f1..7772928ee48f 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb | |||
@@ -101,3 +101,46 @@ Description: | |||
101 | Users: | 101 | Users: |
102 | USB PM tool | 102 | USB PM tool |
103 | git://git.moblin.org/users/sarah/usb-pm-tool/ | 103 | git://git.moblin.org/users/sarah/usb-pm-tool/ |
104 | |||
105 | What: /sys/bus/usb/device/.../authorized | ||
106 | Date: July 2008 | ||
107 | KernelVersion: 2.6.26 | ||
108 | Contact: David Vrabel <david.vrabel@csr.com> | ||
109 | Description: | ||
110 | Authorized devices are available for use by device | ||
111 | drivers, non-authorized one are not. By default, wired | ||
112 | USB devices are authorized. | ||
113 | |||
114 | Certified Wireless USB devices are not authorized | ||
115 | initially and should be (by writing 1) after the | ||
116 | device has been authenticated. | ||
117 | |||
118 | What: /sys/bus/usb/device/.../wusb_cdid | ||
119 | Date: July 2008 | ||
120 | KernelVersion: 2.6.27 | ||
121 | Contact: David Vrabel <david.vrabel@csr.com> | ||
122 | Description: | ||
123 | For Certified Wireless USB devices only. | ||
124 | |||
125 | A devices's CDID, as 16 space-separated hex octets. | ||
126 | |||
127 | What: /sys/bus/usb/device/.../wusb_ck | ||
128 | Date: July 2008 | ||
129 | KernelVersion: 2.6.27 | ||
130 | Contact: David Vrabel <david.vrabel@csr.com> | ||
131 | Description: | ||
132 | For Certified Wireless USB devices only. | ||
133 | |||
134 | Write the device's connection key (CK) to start the | ||
135 | authentication of the device. The CK is 16 | ||
136 | space-separated hex octets. | ||
137 | |||
138 | What: /sys/bus/usb/device/.../wusb_disconnect | ||
139 | Date: July 2008 | ||
140 | KernelVersion: 2.6.27 | ||
141 | Contact: David Vrabel <david.vrabel@csr.com> | ||
142 | Description: | ||
143 | For Certified Wireless USB devices only. | ||
144 | |||
145 | Write a 1 to force the device to disconnect | ||
146 | (equivalent to unplugging a wired USB device). | ||
diff --git a/Documentation/ABI/testing/sysfs-class-usb_host b/Documentation/ABI/testing/sysfs-class-usb_host new file mode 100644 index 000000000000..46b66ad1f1b4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-usb_host | |||
@@ -0,0 +1,25 @@ | |||
1 | What: /sys/class/usb_host/usb_hostN/wusb_chid | ||
2 | Date: July 2008 | ||
3 | KernelVersion: 2.6.27 | ||
4 | Contact: David Vrabel <david.vrabel@csr.com> | ||
5 | Description: | ||
6 | Write the CHID (16 space-separated hex octets) for this host controller. | ||
7 | This starts the host controller, allowing it to accept connection from | ||
8 | WUSB devices. | ||
9 | |||
10 | Set an all zero CHID to stop the host controller. | ||
11 | |||
12 | What: /sys/class/usb_host/usb_hostN/wusb_trust_timeout | ||
13 | Date: July 2008 | ||
14 | KernelVersion: 2.6.27 | ||
15 | Contact: David Vrabel <david.vrabel@csr.com> | ||
16 | Description: | ||
17 | Devices that haven't sent a WUSB packet to the host | ||
18 | within 'wusb_trust_timeout' ms are considered to have | ||
19 | disconnected and are removed. The default value of | ||
20 | 4000 ms is the value required by the WUSB | ||
21 | specification. | ||
22 | |||
23 | Since this relates to security (specifically, the | ||
24 | lifetime of PTKs and GTKs) it should not be changed | ||
25 | from the default. | ||
diff --git a/Documentation/ABI/testing/sysfs-class-uwb_rc b/Documentation/ABI/testing/sysfs-class-uwb_rc new file mode 100644 index 000000000000..a0d18dbeb7a9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-uwb_rc | |||
@@ -0,0 +1,144 @@ | |||
1 | What: /sys/class/uwb_rc | ||
2 | Date: July 2008 | ||
3 | KernelVersion: 2.6.27 | ||
4 | Contact: linux-usb@vger.kernel.org | ||
5 | Description: | ||
6 | Interfaces for WiMedia Ultra Wideband Common Radio | ||
7 | Platform (UWB) radio controllers. | ||
8 | |||
9 | Familiarity with the ECMA-368 'High Rate Ultra | ||
10 | Wideband MAC and PHY Specification' is assumed. | ||
11 | |||
12 | What: /sys/class/uwb_rc/beacon_timeout_ms | ||
13 | Date: July 2008 | ||
14 | KernelVersion: 2.6.27 | ||
15 | Description: | ||
16 | If no beacons are received from a device for at least | ||
17 | this time, the device will be considered to have gone | ||
18 | and it will be removed. The default is 3 superframes | ||
19 | (~197 ms) as required by the specification. | ||
20 | |||
21 | What: /sys/class/uwb_rc/uwbN/ | ||
22 | Date: July 2008 | ||
23 | KernelVersion: 2.6.27 | ||
24 | Contact: linux-usb@vger.kernel.org | ||
25 | Description: | ||
26 | An individual UWB radio controller. | ||
27 | |||
28 | What: /sys/class/uwb_rc/uwbN/beacon | ||
29 | Date: July 2008 | ||
30 | KernelVersion: 2.6.27 | ||
31 | Contact: linux-usb@vger.kernel.org | ||
32 | Description: | ||
33 | Write: | ||
34 | |||
35 | <channel> [<bpst offset>] | ||
36 | |||
37 | to start beaconing on a specific channel, or stop | ||
38 | beaconing if <channel> is -1. Valid channels depends | ||
39 | on the radio controller's supported band groups. | ||
40 | |||
41 | <bpst offset> may be used to try and join a specific | ||
42 | beacon group if more than one was found during a scan. | ||
43 | |||
44 | What: /sys/class/uwb_rc/uwbN/scan | ||
45 | Date: July 2008 | ||
46 | KernelVersion: 2.6.27 | ||
47 | Contact: linux-usb@vger.kernel.org | ||
48 | Description: | ||
49 | Write: | ||
50 | |||
51 | <channel> <type> [<bpst offset>] | ||
52 | |||
53 | to start (or stop) scanning on a channel. <type> is one of: | ||
54 | 0 - scan | ||
55 | 1 - scan outside BP | ||
56 | 2 - scan while inactive | ||
57 | 3 - scanning disabled | ||
58 | 4 - scan (with start time of <bpst offset>) | ||
59 | |||
60 | What: /sys/class/uwb_rc/uwbN/mac_address | ||
61 | Date: July 2008 | ||
62 | KernelVersion: 2.6.27 | ||
63 | Contact: linux-usb@vger.kernel.org | ||
64 | Description: | ||
65 | The EUI-48, in colon-separated hex octets, for this | ||
66 | radio controller. A write will change the radio | ||
67 | controller's EUI-48 but only do so while the device is | ||
68 | not beaconing or scanning. | ||
69 | |||
70 | What: /sys/class/uwb_rc/uwbN/wusbhc | ||
71 | Date: July 2008 | ||
72 | KernelVersion: 2.6.27 | ||
73 | Contact: linux-usb@vger.kernel.org | ||
74 | Description: | ||
75 | A symlink to the device (if any) of the WUSB Host | ||
76 | Controller PAL using this radio controller. | ||
77 | |||
78 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/ | ||
79 | Date: July 2008 | ||
80 | KernelVersion: 2.6.27 | ||
81 | Contact: linux-usb@vger.kernel.org | ||
82 | Description: | ||
83 | A neighbour UWB device that has either been detected | ||
84 | as part of a scan or is a member of the radio | ||
85 | controllers beacon group. | ||
86 | |||
87 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/BPST | ||
88 | Date: July 2008 | ||
89 | KernelVersion: 2.6.27 | ||
90 | Contact: linux-usb@vger.kernel.org | ||
91 | Description: | ||
92 | The time (using the radio controllers internal 1 ms | ||
93 | interval superframe timer) of the last beacon from | ||
94 | this device was received. | ||
95 | |||
96 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/DevAddr | ||
97 | Date: July 2008 | ||
98 | KernelVersion: 2.6.27 | ||
99 | Contact: linux-usb@vger.kernel.org | ||
100 | Description: | ||
101 | The current DevAddr of this device in colon separated | ||
102 | hex octets. | ||
103 | |||
104 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/EUI_48 | ||
105 | Date: July 2008 | ||
106 | KernelVersion: 2.6.27 | ||
107 | Contact: linux-usb@vger.kernel.org | ||
108 | Description: | ||
109 | |||
110 | The EUI-48 of this device in colon separated hex | ||
111 | octets. | ||
112 | |||
113 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/BPST | ||
114 | Date: July 2008 | ||
115 | KernelVersion: 2.6.27 | ||
116 | Contact: linux-usb@vger.kernel.org | ||
117 | Description: | ||
118 | |||
119 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/IEs | ||
120 | Date: July 2008 | ||
121 | KernelVersion: 2.6.27 | ||
122 | Contact: linux-usb@vger.kernel.org | ||
123 | Description: | ||
124 | The latest IEs included in this device's beacon, in | ||
125 | space separated hex octets with one IE per line. | ||
126 | |||
127 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/LQE | ||
128 | Date: July 2008 | ||
129 | KernelVersion: 2.6.27 | ||
130 | Contact: linux-usb@vger.kernel.org | ||
131 | Description: | ||
132 | Link Quality Estimate - the Signal to Noise Ratio | ||
133 | (SNR) of all packets received from this device in dB. | ||
134 | This gives an estimate on a suitable PHY rate. Refer | ||
135 | to [ECMA-368] section 13.3 for more details. | ||
136 | |||
137 | What: /sys/class/uwb_rc/uwbN/<EUI-48>/RSSI | ||
138 | Date: July 2008 | ||
139 | KernelVersion: 2.6.27 | ||
140 | Contact: linux-usb@vger.kernel.org | ||
141 | Description: | ||
142 | Received Signal Strength Indication - the strength of | ||
143 | the received signal in dB. LQE is a more useful | ||
144 | measure of the radio link quality. | ||
diff --git a/Documentation/ABI/testing/sysfs-wusb_cbaf b/Documentation/ABI/testing/sysfs-wusb_cbaf new file mode 100644 index 000000000000..a99c5f86a37a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-wusb_cbaf | |||
@@ -0,0 +1,100 @@ | |||
1 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_* | ||
2 | Date: August 2008 | ||
3 | KernelVersion: 2.6.27 | ||
4 | Contact: David Vrabel <david.vrabel@csr.com> | ||
5 | Description: | ||
6 | Various files for managing Cable Based Association of | ||
7 | (wireless) USB devices. | ||
8 | |||
9 | The sequence of operations should be: | ||
10 | |||
11 | 1. Device is plugged in. | ||
12 | |||
13 | 2. The connection manager (CM) sees a device with CBA capability. | ||
14 | (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE). | ||
15 | |||
16 | 3. The CM writes the host name, supported band groups, | ||
17 | and the CHID (host ID) into the wusb_host_name, | ||
18 | wusb_host_band_groups and wusb_chid files. These | ||
19 | get sent to the device and the CDID (if any) for | ||
20 | this host is requested. | ||
21 | |||
22 | 4. The CM can verify that the device's supported band | ||
23 | groups (wusb_device_band_groups) are compatible | ||
24 | with the host. | ||
25 | |||
26 | 5. The CM reads the wusb_cdid file. | ||
27 | |||
28 | 6. The CM looks it up its database. | ||
29 | |||
30 | - If it has a matching CHID,CDID entry, the device | ||
31 | has been authorized before and nothing further | ||
32 | needs to be done. | ||
33 | |||
34 | - If the CDID is zero (or the CM doesn't find a | ||
35 | matching CDID in its database), the device is | ||
36 | assumed to be not known. The CM may associate | ||
37 | the host with device by: writing a randomly | ||
38 | generated CDID to wusb_cdid and then a random CK | ||
39 | to wusb_ck (this uploads the new CC to the | ||
40 | device). | ||
41 | |||
42 | CMD may choose to prompt the user before | ||
43 | associating with a new device. | ||
44 | |||
45 | 7. Device is unplugged. | ||
46 | |||
47 | References: | ||
48 | [WUSB-AM] Association Models Supplement to the | ||
49 | Certified Wireless Universal Serial Bus | ||
50 | Specification, version 1.0. | ||
51 | |||
52 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_chid | ||
53 | Date: August 2008 | ||
54 | KernelVersion: 2.6.27 | ||
55 | Contact: David Vrabel <david.vrabel@csr.com> | ||
56 | Description: | ||
57 | The CHID of the host formatted as 16 space-separated | ||
58 | hex octets. | ||
59 | |||
60 | Writes fetches device's supported band groups and the | ||
61 | the CDID for any existing association with this host. | ||
62 | |||
63 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_host_name | ||
64 | Date: August 2008 | ||
65 | KernelVersion: 2.6.27 | ||
66 | Contact: David Vrabel <david.vrabel@csr.com> | ||
67 | Description: | ||
68 | A friendly name for the host as a UTF-8 encoded string. | ||
69 | |||
70 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_host_band_groups | ||
71 | Date: August 2008 | ||
72 | KernelVersion: 2.6.27 | ||
73 | Contact: David Vrabel <david.vrabel@csr.com> | ||
74 | Description: | ||
75 | The band groups supported by the host, in the format | ||
76 | defined in [WUSB-AM]. | ||
77 | |||
78 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_device_band_groups | ||
79 | Date: August 2008 | ||
80 | KernelVersion: 2.6.27 | ||
81 | Contact: David Vrabel <david.vrabel@csr.com> | ||
82 | Description: | ||
83 | The band groups supported by the device, in the format | ||
84 | defined in [WUSB-AM]. | ||
85 | |||
86 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_cdid | ||
87 | Date: August 2008 | ||
88 | KernelVersion: 2.6.27 | ||
89 | Contact: David Vrabel <david.vrabel@csr.com> | ||
90 | Description: | ||
91 | The device's CDID formatted as 16 space-separated hex | ||
92 | octets. | ||
93 | |||
94 | What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_ck | ||
95 | Date: August 2008 | ||
96 | KernelVersion: 2.6.27 | ||
97 | Contact: David Vrabel <david.vrabel@csr.com> | ||
98 | Description: | ||
99 | Write 16 space-separated random, hex octets to | ||
100 | associate with the device. | ||
diff --git a/Documentation/usb/WUSB-Design-overview.txt b/Documentation/usb/WUSB-Design-overview.txt new file mode 100644 index 000000000000..4c3d62c7843a --- /dev/null +++ b/Documentation/usb/WUSB-Design-overview.txt | |||
@@ -0,0 +1,448 @@ | |||
1 | |||
2 | Linux UWB + Wireless USB + WiNET | ||
3 | |||
4 | (C) 2005-2006 Intel Corporation | ||
5 | Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License version | ||
9 | 2 as published by the Free Software Foundation. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | 02110-1301, USA. | ||
20 | |||
21 | |||
22 | Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for | ||
23 | updated content. | ||
24 | |||
25 | * Design-overview.txt-1.8 | ||
26 | |||
27 | This code implements a Ultra Wide Band stack for Linux, as well as | ||
28 | drivers for the the USB based UWB radio controllers defined in the | ||
29 | Wireless USB 1.0 specification (including Wireless USB host controller | ||
30 | and an Intel WiNET controller). | ||
31 | |||
32 | 1. Introduction | ||
33 | 1. HWA: Host Wire adapters, your Wireless USB dongle | ||
34 | |||
35 | 2. DWA: Device Wired Adaptor, a Wireless USB hub for wired | ||
36 | devices | ||
37 | 3. WHCI: Wireless Host Controller Interface, the PCI WUSB host | ||
38 | adapter | ||
39 | 2. The UWB stack | ||
40 | 1. Devices and hosts: the basic structure | ||
41 | |||
42 | 2. Host Controller life cycle | ||
43 | |||
44 | 3. On the air: beacons and enumerating the radio neighborhood | ||
45 | |||
46 | 4. Device lists | ||
47 | 5. Bandwidth allocation | ||
48 | |||
49 | 3. Wireless USB Host Controller drivers | ||
50 | |||
51 | 4. Glossary | ||
52 | |||
53 | |||
54 | Introduction | ||
55 | |||
56 | UWB is a wide-band communication protocol that is to serve also as the | ||
57 | low-level protocol for others (much like TCP sits on IP). Currently | ||
58 | these others are Wireless USB and TCP/IP, but seems Bluetooth and | ||
59 | Firewire/1394 are coming along. | ||
60 | |||
61 | UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of | ||
62 | ~-41dB (or 0.074 uW/MHz--geography specific data is still being | ||
63 | negotiated w/ regulators, so watch for changes). That band is divided in | ||
64 | a bunch of ~1.5 GHz wide channels (or band groups) composed of three | ||
65 | subbands/subchannels (528 MHz each). Each channel is independent of each | ||
66 | other, so you could consider them different "busses". Initially this | ||
67 | driver considers them all a single one. | ||
68 | |||
69 | Radio time is divided in 65536 us long /superframes/, each one divided | ||
70 | in 256 256us long /MASs/ (Media Allocation Slots), which are the basic | ||
71 | time/media allocation units for transferring data. At the beginning of | ||
72 | each superframe there is a Beacon Period (BP), where every device | ||
73 | transmit its beacon on a single MAS. The length of the BP depends on how | ||
74 | many devices are present and the length of their beacons. | ||
75 | |||
76 | Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16 | ||
77 | bit address) and send periodic beacons to advertise themselves and pass | ||
78 | info on what they are and do. They advertise their capabilities and a | ||
79 | bunch of other stuff. | ||
80 | |||
81 | The different logical parts of this driver are: | ||
82 | |||
83 | * | ||
84 | |||
85 | *UWB*: the Ultra-Wide-Band stack -- manages the radio and | ||
86 | associated spectrum to allow for devices sharing it. Allows to | ||
87 | control bandwidth assingment, beaconing, scanning, etc | ||
88 | |||
89 | * | ||
90 | |||
91 | *WUSB*: the layer that sits on top of UWB to provide Wireless USB. | ||
92 | The Wireless USB spec defines means to control a UWB radio and to | ||
93 | do the actual WUSB. | ||
94 | |||
95 | |||
96 | HWA: Host Wire adapters, your Wireless USB dongle | ||
97 | |||
98 | WUSB also defines a device called a Host Wire Adaptor (HWA), which in | ||
99 | mere terms is a USB dongle that enables your PC to have UWB and Wireless | ||
100 | USB. The Wireless USB Host Controller in a HWA looks to the host like a | ||
101 | [Wireless] USB controller connected via USB (!) | ||
102 | |||
103 | The HWA itself is broken in two or three main interfaces: | ||
104 | |||
105 | * | ||
106 | |||
107 | *RC*: Radio control -- this implements an interface to the | ||
108 | Ultra-Wide-Band radio controller. The driver for this implements a | ||
109 | USB-based UWB Radio Controller to the UWB stack. | ||
110 | |||
111 | * | ||
112 | |||
113 | *HC*: the wireless USB host controller. It looks like a USB host | ||
114 | whose root port is the radio and the WUSB devices connect to it. | ||
115 | To the system it looks like a separate USB host. The driver (will) | ||
116 | implement a USB host controller (similar to UHCI, OHCI or EHCI) | ||
117 | for which the root hub is the radio...To reiterate: it is a USB | ||
118 | controller that is connected via USB instead of PCI. | ||
119 | |||
120 | * | ||
121 | |||
122 | *WINET*: some HW provide a WiNET interface (IP over UWB). This | ||
123 | package provides a driver for it (it looks like a network | ||
124 | interface, winetX). The driver detects when there is a link up for | ||
125 | their type and kick into gear. | ||
126 | |||
127 | |||
128 | DWA: Device Wired Adaptor, a Wireless USB hub for wired devices | ||
129 | |||
130 | These are the complement to HWAs. They are a USB host for connecting | ||
131 | wired devices, but it is connected to your PC connected via Wireless | ||
132 | USB. To the system it looks like yet another USB host. To the untrained | ||
133 | eye, it looks like a hub that connects upstream wirelessly. | ||
134 | |||
135 | We still offer no support for this; however, it should share a lot of | ||
136 | code with the HWA-RC driver; there is a bunch of factorization work that | ||
137 | has been done to support that in upcoming releases. | ||
138 | |||
139 | |||
140 | WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter | ||
141 | |||
142 | This is your usual PCI device that implements WHCI. Similar in concept | ||
143 | to EHCI, it allows your wireless USB devices (including DWAs) to connect | ||
144 | to your host via a PCI interface. As in the case of the HWA, it has a | ||
145 | Radio Control interface and the WUSB Host Controller interface per se. | ||
146 | |||
147 | There is still no driver support for this, but will be in upcoming | ||
148 | releases. | ||
149 | |||
150 | |||
151 | The UWB stack | ||
152 | |||
153 | The main mission of the UWB stack is to keep a tally of which devices | ||
154 | are in radio proximity to allow drivers to connect to them. As well, it | ||
155 | provides an API for controlling the local radio controllers (RCs from | ||
156 | now on), such as to start/stop beaconing, scan, allocate bandwidth, etc. | ||
157 | |||
158 | |||
159 | Devices and hosts: the basic structure | ||
160 | |||
161 | The main building block here is the UWB device (struct uwb_dev). For | ||
162 | each device that pops up in radio presence (ie: the UWB host receives a | ||
163 | beacon from it) you get a struct uwb_dev that will show up in | ||
164 | /sys/class/uwb and in /sys/bus/uwb/devices. | ||
165 | |||
166 | For each RC that is detected, a new struct uwb_rc is created. In turn, a | ||
167 | RC is also a device, so they also show in /sys/class/uwb and | ||
168 | /sys/bus/uwb/devices, but at the same time, only radio controllers show | ||
169 | up in /sys/class/uwb_rc. | ||
170 | |||
171 | * | ||
172 | |||
173 | [*] The reason for RCs being also devices is that not only we can | ||
174 | see them while enumerating the system device tree, but also on the | ||
175 | radio (their beacons and stuff), so the handling has to be | ||
176 | likewise to that of a device. | ||
177 | |||
178 | Each RC driver is implemented by a separate driver that plugs into the | ||
179 | interface that the UWB stack provides through a struct uwb_rc_ops. The | ||
180 | spec creators have been nice enough to make the message format the same | ||
181 | for HWA and WHCI RCs, so the driver is really a very thin transport that | ||
182 | moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/] | ||
183 | and sends the replies and notifications back to the API | ||
184 | [/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that | ||
185 | is chartered, among other things, to keep the tab of how the UWB radio | ||
186 | neighborhood looks, creating and destroying devices as they show up or | ||
187 | dissapear. | ||
188 | |||
189 | Command execution is very simple: a command block is sent and a event | ||
190 | block or reply is expected back. For sending/receiving command/events, a | ||
191 | handle called /neh/ (Notification/Event Handle) is opened with | ||
192 | /uwb_rc_neh_open()/. | ||
193 | |||
194 | The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for | ||
195 | the USB connected HWA. Eventually, drivers/whci-rc.c will do the same | ||
196 | for the PCI connected WHCI controller. | ||
197 | |||
198 | |||
199 | Host Controller life cycle | ||
200 | |||
201 | So let's say we connect a dongle to the system: it is detected and | ||
202 | firmware uploaded if needed [for Intel's i1480 | ||
203 | /drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated. | ||
204 | Now we have a real HWA device connected and | ||
205 | /drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the | ||
206 | Wire-Adaptor environment and then suck it into the UWB stack's vision of | ||
207 | the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/]. | ||
208 | |||
209 | * | ||
210 | |||
211 | [*] The stack should put a new RC to scan for devices | ||
212 | [/uwb_rc_scan()/] so it finds what's available around and tries to | ||
213 | connect to them, but this is policy stuff and should be driven | ||
214 | from user space. As of now, the operator is expected to do it | ||
215 | manually; see the release notes for documentation on the procedure. | ||
216 | |||
217 | When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/ | ||
218 | takes time of tearing everything down safely (or not...). | ||
219 | |||
220 | |||
221 | On the air: beacons and enumerating the radio neighborhood | ||
222 | |||
223 | So assuming we have devices and we have agreed for a channel to connect | ||
224 | on (let's say 9), we put the new RC to beacon: | ||
225 | |||
226 | * | ||
227 | |||
228 | $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon | ||
229 | |||
230 | Now it is visible. If there were other devices in the same radio channel | ||
231 | and beacon group (that's what the zero is for), the dongle's radio | ||
232 | control interface will send beacon notifications on its | ||
233 | notification/event endpoint (NEEP). The beacon notifications are part of | ||
234 | the event stream that is funneled into the API with | ||
235 | /drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB | ||
236 | daemon through a notification list. | ||
237 | |||
238 | UWBD wakes up and scans the event list; finds a beacon and adds it to | ||
239 | the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from | ||
240 | the same device, he considers it to be 'onair' and creates a new device | ||
241 | [/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons | ||
242 | are received in some time, the device is considered gone and wiped out | ||
243 | [uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge | ||
244 | the beacon cache of dead devices]. | ||
245 | |||
246 | |||
247 | Device lists | ||
248 | |||
249 | All UWB devices are kept in the list of the struct bus_type uwb_bus. | ||
250 | |||
251 | |||
252 | Bandwidth allocation | ||
253 | |||
254 | The UWB stack maintains a local copy of DRP availability through | ||
255 | processing of incoming *DRP Availability Change* notifications. This | ||
256 | local copy is currently used to present the current bandwidth | ||
257 | availability to the user through the sysfs file | ||
258 | /sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth | ||
259 | availability information will be used by the bandwidth reservation | ||
260 | routines. | ||
261 | |||
262 | The bandwidth reservation routines are in progress and are thus not | ||
263 | present in the current release. When completed they will enable a user | ||
264 | to initiate DRP reservation requests through interaction with sysfs. DRP | ||
265 | reservation requests from remote UWB devices will also be handled. The | ||
266 | bandwidth management done by the UWB stack will include callbacks to the | ||
267 | higher layers will enable the higher layers to use the reservations upon | ||
268 | completion. [Note: The bandwidth reservation work is in progress and | ||
269 | subject to change.] | ||
270 | |||
271 | |||
272 | Wireless USB Host Controller drivers | ||
273 | |||
274 | *WARNING* This section needs a lot of work! | ||
275 | |||
276 | As explained above, there are three different types of HCs in the WUSB | ||
277 | world: HWA-HC, DWA-HC and WHCI-HC. | ||
278 | |||
279 | HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB | ||
280 | connected controllers), and their transfer management system is almost | ||
281 | identical. So is their notification delivery system. | ||
282 | |||
283 | HWA-HC and WHCI-HC share that they are both WUSB host controllers, so | ||
284 | they have to deal with WUSB device life cycle and maintenance, wireless | ||
285 | root-hub | ||
286 | |||
287 | HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has | ||
288 | three endpoints (Notifications, Data Transfer In and Data Transfer | ||
289 | Out--known as NEP, DTI and DTO in the code). | ||
290 | |||
291 | We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster | ||
292 | ID and tell the HC to use all that. Then we start it. This means the HC | ||
293 | starts sending MMCs. | ||
294 | |||
295 | * | ||
296 | |||
297 | The MMCs are blocks of data defined somewhere in the WUSB1.0 spec | ||
298 | that define a stream in the UWB channel time allocated for sending | ||
299 | WUSB IEs (host to device commands/notifications) and Device | ||
300 | Notifications (device initiated to host). Each host defines a | ||
301 | unique Wireless USB cluster through MMCs. Devices can connect to a | ||
302 | single cluster at the time. The IEs are Information Elements, and | ||
303 | among them are the bandwidth allocations that tell each device | ||
304 | when can they transmit or receive. | ||
305 | |||
306 | Now it all depends on external stimuli. | ||
307 | |||
308 | *New device connection* | ||
309 | |||
310 | A new device pops up, it scans the radio looking for MMCs that give out | ||
311 | the existence of Wireless USB channels. Once one (or more) are found, | ||
312 | selects which one to connect to. Sends a /DN_Connect/ (device | ||
313 | notification connect) during the DNTS (Device Notification Time | ||
314 | Slot--announced in the MMCs | ||
315 | |||
316 | HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery | ||
317 | into /devconnect/). This process starts the authentication process for | ||
318 | the device. First we allocate a /fake port/ and assign an | ||
319 | unauthenticated address (128 to 255--what we really do is | ||
320 | 0x80 | fake_port_idx). We fiddle with the fake port status and /khubd/ | ||
321 | sees a new connection, so he moves on to enable the fake port with a reset. | ||
322 | |||
323 | So now we are in the reset path -- we know we have a non-yet enumerated | ||
324 | device with an unauthorized address; we ask user space to authenticate | ||
325 | (FIXME: not yet done, similar to bluetooth pairing), then we do the key | ||
326 | exchange (FIXME: not yet done) and issue a /set address 0/ to bring the | ||
327 | device to the default state. Device is authenticated. | ||
328 | |||
329 | From here, the USB stack takes control through the usb_hcd ops. khubd | ||
330 | has seen the port status changes, as we have been toggling them. It will | ||
331 | start enumerating and doing transfers through usb_hcd->urb_enqueue() to | ||
332 | read descriptors and move our data. | ||
333 | |||
334 | *Device life cycle and keep alives* | ||
335 | |||
336 | Everytime there is a succesful transfer to/from a device, we update a | ||
337 | per-device activity timestamp. If not, every now and then we check and | ||
338 | if the activity timestamp gets old, we ping the device by sending it a | ||
339 | Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this | ||
340 | arrives to us as a notification through | ||
341 | devconnect.c:wusb_handle_dn_alive(). If a device times out, we | ||
342 | disconnect it from the system (cleaning up internal information and | ||
343 | toggling the bits in the fake hub port, which kicks khubd into removing | ||
344 | the rest of the stuff). | ||
345 | |||
346 | This is done through devconnect:__wusb_check_devs(), which will scan the | ||
347 | device list looking for whom needs refreshing. | ||
348 | |||
349 | If the device wants to disconnect, it will either die (ugly) or send a | ||
350 | /DN_Disconnect/ that will prompt a disconnection from the system. | ||
351 | |||
352 | *Sending and receiving data* | ||
353 | |||
354 | Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is | ||
355 | /aimed/ at an endpoint in a WUSB device. This is the same for HWAs and | ||
356 | DWAs. | ||
357 | |||
358 | Each HC has a number of rpipes and buffers that can be assigned to them; | ||
359 | when doing a data transfer (xfer), first the rpipe has to be aimed and | ||
360 | prepared (buffers assigned), then we can start queueing requests for | ||
361 | data in or out. | ||
362 | |||
363 | Data buffers have to be segmented out before sending--so we send first a | ||
364 | header (segment request) and then if there is any data, a data buffer | ||
365 | immediately after to the DTI interface (yep, even the request). If our | ||
366 | buffer is bigger than the max segment size, then we just do multiple | ||
367 | requests. | ||
368 | |||
369 | [This sucks, because doing USB scatter gatter in Linux is resource | ||
370 | intensive, if any...not that the current approach is not. It just has to | ||
371 | be cleaned up a lot :)]. | ||
372 | |||
373 | If reading, we don't send data buffers, just the segment headers saying | ||
374 | we want to read segments. | ||
375 | |||
376 | When the xfer is executed, we receive a notification that says data is | ||
377 | ready in the DTI endpoint (handled through | ||
378 | xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a | ||
379 | descriptor that gives us the status of the transfer, its identification | ||
380 | (given when we issued it) and the segment number. If it was a data read, | ||
381 | we issue another URB to read into the destination buffer the chunk of | ||
382 | data coming out of the remote endpoint. Done, wait for the next guy. The | ||
383 | callbacks for the URBs issued from here are the ones that will declare | ||
384 | the xfer complete at some point and call it's callback. | ||
385 | |||
386 | Seems simple, but the implementation is not trivial. | ||
387 | |||
388 | * | ||
389 | |||
390 | *WARNING* Old!! | ||
391 | |||
392 | The main xfer descriptor, wa_xfer (equivalent to a URB) contains an | ||
393 | array of segments, tallys on segments and buffers and callback | ||
394 | information. Buried in there is a lot of URBs for executing the segments | ||
395 | and buffer transfers. | ||
396 | |||
397 | For OUT xfers, there is an array of segments, one URB for each, another | ||
398 | one of buffer URB. When submitting, we submit URBs for segment request | ||
399 | 1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer | ||
400 | result data; when all the segments are complete, we call the callback to | ||
401 | finalize the transfer. | ||
402 | |||
403 | For IN xfers, we only issue URBs for the segments we want to read and | ||
404 | then wait for the xfer result data. | ||
405 | |||
406 | *URB mapping into xfers* | ||
407 | |||
408 | This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an | ||
409 | rpipe to the endpoint where we have to transmit, create a transfer | ||
410 | context (wa_xfer) and submit it. When the xfer is done, our callback is | ||
411 | called and we assign the status bits and release the xfer resources. | ||
412 | |||
413 | In dequeue() we are basically cancelling/aborting the transfer. We issue | ||
414 | a xfer abort request to the HC, cancell all the URBs we had submitted | ||
415 | and not yet done and when all that is done, the xfer callback will be | ||
416 | called--this will call the URB callback. | ||
417 | |||
418 | |||
419 | Glossary | ||
420 | |||
421 | *DWA* -- Device Wire Adapter | ||
422 | |||
423 | USB host, wired for downstream devices, upstream connects wirelessly | ||
424 | with Wireless USB. | ||
425 | |||
426 | *EVENT* -- Response to a command on the NEEP | ||
427 | |||
428 | *HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB | ||
429 | |||
430 | *NEH* -- Notification/Event Handle | ||
431 | |||
432 | Handle/file descriptor for receiving notifications or events. The WA | ||
433 | code requires you to get one of this to listen for notifications or | ||
434 | events on the NEEP. | ||
435 | |||
436 | *NEEP* -- Notification/Event EndPoint | ||
437 | |||
438 | Stuff related to the management of the first endpoint of a HWA USB | ||
439 | dongle that is used to deliver an stream of events and notifications to | ||
440 | the host. | ||
441 | |||
442 | *NOTIFICATION* -- Message coming in the NEEP as response to something. | ||
443 | |||
444 | *RC* -- Radio Control | ||
445 | |||
446 | Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by | ||
447 | InakyPerezGonzalez) | ||
448 | |||
diff --git a/Documentation/usb/wusb-cbaf b/Documentation/usb/wusb-cbaf new file mode 100644 index 000000000000..2e78b70f3adc --- /dev/null +++ b/Documentation/usb/wusb-cbaf | |||
@@ -0,0 +1,139 @@ | |||
1 | #! /bin/bash | ||
2 | # | ||
3 | |||
4 | set -e | ||
5 | |||
6 | progname=$(basename $0) | ||
7 | function help | ||
8 | { | ||
9 | cat <<EOF | ||
10 | Usage: $progname COMMAND DEVICEs [ARGS] | ||
11 | |||
12 | Command for manipulating the pairing/authentication credentials of a | ||
13 | Wireless USB device that supports wired-mode Cable-Based-Association. | ||
14 | |||
15 | Works in conjunction with the wusb-cba.ko driver from http://linuxuwb.org. | ||
16 | |||
17 | |||
18 | DEVICE | ||
19 | |||
20 | sysfs path to the device to authenticate; for example, both this | ||
21 | guys are the same: | ||
22 | |||
23 | /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.4/1-4.4:1.1 | ||
24 | /sys/bus/usb/drivers/wusb-cbaf/1-4.4:1.1 | ||
25 | |||
26 | COMMAND/ARGS are | ||
27 | |||
28 | start | ||
29 | |||
30 | Start a WUSB host controller (by setting up a CHID) | ||
31 | |||
32 | set-chid DEVICE HOST-CHID HOST-BANDGROUP HOST-NAME | ||
33 | |||
34 | Sets host information in the device; after this you can call the | ||
35 | get-cdid to see how does this device report itself to us. | ||
36 | |||
37 | get-cdid DEVICE | ||
38 | |||
39 | Get the device ID associated to the HOST-CHDI we sent with | ||
40 | 'set-chid'. We might not know about it. | ||
41 | |||
42 | set-cc DEVICE | ||
43 | |||
44 | If we allow the device to connect, set a random new CDID and CK | ||
45 | (connection key). Device saves them for the next time it wants to | ||
46 | connect wireless. We save them for that next time also so we can | ||
47 | authenticate the device (when we see the CDID he uses to id | ||
48 | itself) and the CK to crypto talk to it. | ||
49 | |||
50 | CHID is always 16 hex bytes in 'XX YY ZZ...' form | ||
51 | BANDGROUP is almost always 0001 | ||
52 | |||
53 | Examples: | ||
54 | |||
55 | You can default most arguments to '' to get a sane value: | ||
56 | |||
57 | $ $progname set-chid '' '' '' "My host name" | ||
58 | |||
59 | A full sequence: | ||
60 | |||
61 | $ $progname set-chid '' '' '' "My host name" | ||
62 | $ $progname get-cdid '' | ||
63 | $ $progname set-cc '' | ||
64 | |||
65 | EOF | ||
66 | } | ||
67 | |||
68 | |||
69 | # Defaults | ||
70 | # FIXME: CHID should come from a database :), band group from the host | ||
71 | host_CHID="00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff" | ||
72 | host_band_group="0001" | ||
73 | host_name=$(hostname) | ||
74 | |||
75 | devs="$(echo /sys/bus/usb/drivers/wusb-cbaf/[0-9]*)" | ||
76 | hdevs="$(for h in /sys/class/uwb_rc/*/wusbhc; do readlink -f $h; done)" | ||
77 | |||
78 | result=0 | ||
79 | case $1 in | ||
80 | start) | ||
81 | for dev in ${2:-$hdevs} | ||
82 | do | ||
83 | uwb_rc=$(readlink -f $dev/uwb_rc) | ||
84 | if cat $uwb_rc/beacon | grep -q -- "-1" | ||
85 | then | ||
86 | echo 13 0 > $uwb_rc/beacon | ||
87 | echo I: started beaconing on ch 13 on $(basename $uwb_rc) >&2 | ||
88 | fi | ||
89 | echo $host_CHID > $dev/wusb_chid | ||
90 | echo I: started host $(basename $dev) >&2 | ||
91 | done | ||
92 | ;; | ||
93 | stop) | ||
94 | for dev in ${2:-$hdevs} | ||
95 | do | ||
96 | echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid | ||
97 | echo I: stopped host $(basename $dev) >&2 | ||
98 | uwb_rc=$(readlink -f $dev/uwb_rc) | ||
99 | echo -1 | cat > $uwb_rc/beacon | ||
100 | echo I: stopped beaconing on $(basename $uwb_rc) >&2 | ||
101 | done | ||
102 | ;; | ||
103 | set-chid) | ||
104 | shift | ||
105 | for dev in ${2:-$devs}; do | ||
106 | echo "${4:-$host_name}" > $dev/wusb_host_name | ||
107 | echo "${3:-$host_band_group}" > $dev/wusb_host_band_groups | ||
108 | echo ${2:-$host_CHID} > $dev/wusb_chid | ||
109 | done | ||
110 | ;; | ||
111 | get-cdid) | ||
112 | for dev in ${2:-$devs} | ||
113 | do | ||
114 | cat $dev/wusb_cdid | ||
115 | done | ||
116 | ;; | ||
117 | set-cc) | ||
118 | for dev in ${2:-$devs}; do | ||
119 | shift | ||
120 | CDID="$(head --bytes=16 /dev/urandom | od -tx1 -An)" | ||
121 | CK="$(head --bytes=16 /dev/urandom | od -tx1 -An)" | ||
122 | echo "$CDID" > $dev/wusb_cdid | ||
123 | echo "$CK" > $dev/wusb_ck | ||
124 | |||
125 | echo I: CC set >&2 | ||
126 | echo "CHID: $(cat $dev/wusb_chid)" | ||
127 | echo "CDID:$CDID" | ||
128 | echo "CK: $CK" | ||
129 | done | ||
130 | ;; | ||
131 | help|h|--help|-h) | ||
132 | help | ||
133 | ;; | ||
134 | *) | ||
135 | echo "E: Unknown usage" 1>&2 | ||
136 | help 1>&2 | ||
137 | result=1 | ||
138 | esac | ||
139 | exit $result | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 1d11b56794d8..a2afc494de4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1053,6 +1053,12 @@ L: cbe-oss-dev@ozlabs.org | |||
1053 | W: http://www.ibm.com/developerworks/power/cell/ | 1053 | W: http://www.ibm.com/developerworks/power/cell/ |
1054 | S: Supported | 1054 | S: Supported |
1055 | 1055 | ||
1056 | CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: | ||
1057 | P: David Vrabel | ||
1058 | M: david.vrabel@csr.com | ||
1059 | L: linux-usb@vger.kernel.org | ||
1060 | S: Supported | ||
1061 | |||
1056 | CFAG12864B LCD DRIVER | 1062 | CFAG12864B LCD DRIVER |
1057 | P: Miguel Ojeda Sandonis | 1063 | P: Miguel Ojeda Sandonis |
1058 | M: miguel.ojeda.sandonis@gmail.com | 1064 | M: miguel.ojeda.sandonis@gmail.com |
@@ -4191,6 +4197,12 @@ L: sparclinux@vger.kernel.org | |||
4191 | T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git | 4197 | T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git |
4192 | S: Maintained | 4198 | S: Maintained |
4193 | 4199 | ||
4200 | ULTRA-WIDEBAND (UWB) SUBSYSTEM: | ||
4201 | P: David Vrabel | ||
4202 | M: david.vrabel@csr.com | ||
4203 | L: linux-usb@vger.kernel.org | ||
4204 | S: Supported | ||
4205 | |||
4194 | UNIFORM CDROM DRIVER | 4206 | UNIFORM CDROM DRIVER |
4195 | P: Jens Axboe | 4207 | P: Jens Axboe |
4196 | M: axboe@kernel.dk | 4208 | M: axboe@kernel.dk |
@@ -4616,6 +4628,11 @@ M: zaga@fly.cc.fer.hr | |||
4616 | L: linux-scsi@vger.kernel.org | 4628 | L: linux-scsi@vger.kernel.org |
4617 | S: Maintained | 4629 | S: Maintained |
4618 | 4630 | ||
4631 | WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM | ||
4632 | P: David Vrabel | ||
4633 | M: david.vrabel@csr.com | ||
4634 | S: Maintained | ||
4635 | |||
4619 | WISTRON LAPTOP BUTTON DRIVER | 4636 | WISTRON LAPTOP BUTTON DRIVER |
4620 | P: Miloslav Trmac | 4637 | P: Miloslav Trmac |
4621 | M: mitr@volny.cz | 4638 | M: mitr@volny.cz |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bc0fcde20901..f504c801792f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1256,6 +1256,8 @@ source "drivers/hid/Kconfig" | |||
1256 | 1256 | ||
1257 | source "drivers/usb/Kconfig" | 1257 | source "drivers/usb/Kconfig" |
1258 | 1258 | ||
1259 | source "drivers/uwb/Kconfig" | ||
1260 | |||
1259 | source "drivers/mmc/Kconfig" | 1261 | source "drivers/mmc/Kconfig" |
1260 | 1262 | ||
1261 | source "drivers/memstick/Kconfig" | 1263 | source "drivers/memstick/Kconfig" |
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 07335e719bf8..b17aeea8d620 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
@@ -679,6 +679,8 @@ source "fs/Kconfig" | |||
679 | 679 | ||
680 | source "drivers/usb/Kconfig" | 680 | source "drivers/usb/Kconfig" |
681 | 681 | ||
682 | source "drivers/uwb/Kconfig" | ||
683 | |||
682 | source "arch/cris/Kconfig.debug" | 684 | source "arch/cris/Kconfig.debug" |
683 | 685 | ||
684 | source "security/Kconfig" | 686 | source "security/Kconfig" |
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index bd1995403c67..28f06fd9b7b7 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig | |||
@@ -216,6 +216,8 @@ source "drivers/hwmon/Kconfig" | |||
216 | 216 | ||
217 | source "drivers/usb/Kconfig" | 217 | source "drivers/usb/Kconfig" |
218 | 218 | ||
219 | source "drivers/uwb/Kconfig" | ||
220 | |||
219 | endmenu | 221 | endmenu |
220 | 222 | ||
221 | source "fs/Kconfig" | 223 | source "fs/Kconfig" |
diff --git a/drivers/Kconfig b/drivers/Kconfig index d19b6f5a1106..d38f43f593d4 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -78,6 +78,8 @@ source "drivers/hid/Kconfig" | |||
78 | 78 | ||
79 | source "drivers/usb/Kconfig" | 79 | source "drivers/usb/Kconfig" |
80 | 80 | ||
81 | source "drivers/uwb/Kconfig" | ||
82 | |||
81 | source "drivers/mmc/Kconfig" | 83 | source "drivers/mmc/Kconfig" |
82 | 84 | ||
83 | source "drivers/memstick/Kconfig" | 85 | source "drivers/memstick/Kconfig" |
diff --git a/drivers/Makefile b/drivers/Makefile index 46c8681a07f4..cadc64fe8f68 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -100,3 +100,4 @@ obj-$(CONFIG_SSB) += ssb/ | |||
100 | obj-$(CONFIG_VIRTIO) += virtio/ | 100 | obj-$(CONFIG_VIRTIO) += virtio/ |
101 | obj-$(CONFIG_REGULATOR) += regulator/ | 101 | obj-$(CONFIG_REGULATOR) += regulator/ |
102 | obj-$(CONFIG_STAGING) += staging/ | 102 | obj-$(CONFIG_STAGING) += staging/ |
103 | obj-$(CONFIG_UWB) += uwb/ | ||
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index bcefbddeba50..c23a9857ee67 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -97,6 +97,8 @@ source "drivers/usb/core/Kconfig" | |||
97 | 97 | ||
98 | source "drivers/usb/mon/Kconfig" | 98 | source "drivers/usb/mon/Kconfig" |
99 | 99 | ||
100 | source "drivers/usb/wusbcore/Kconfig" | ||
101 | |||
100 | source "drivers/usb/host/Kconfig" | 102 | source "drivers/usb/host/Kconfig" |
101 | 103 | ||
102 | source "drivers/usb/musb/Kconfig" | 104 | source "drivers/usb/musb/Kconfig" |
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a419c42e880e..8b7c419b876e 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
@@ -16,9 +16,12 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/ | |||
16 | obj-$(CONFIG_USB_SL811_HCD) += host/ | 16 | obj-$(CONFIG_USB_SL811_HCD) += host/ |
17 | obj-$(CONFIG_USB_U132_HCD) += host/ | 17 | obj-$(CONFIG_USB_U132_HCD) += host/ |
18 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ | 18 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ |
19 | obj-$(CONFIG_USB_HWA_HCD) += host/ | ||
19 | 20 | ||
20 | obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ | 21 | obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ |
21 | 22 | ||
23 | obj-$(CONFIG_USB_WUSB) += wusbcore/ | ||
24 | |||
22 | obj-$(CONFIG_USB_ACM) += class/ | 25 | obj-$(CONFIG_USB_ACM) += class/ |
23 | obj-$(CONFIG_USB_PRINTER) += class/ | 26 | obj-$(CONFIG_USB_PRINTER) += class/ |
24 | 27 | ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 228797e54f9c..72fb655e6033 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -305,3 +305,31 @@ config SUPERH_ON_CHIP_R8A66597 | |||
305 | help | 305 | help |
306 | This driver enables support for the on-chip R8A66597 in the | 306 | This driver enables support for the on-chip R8A66597 in the |
307 | SH7366 and SH7723 processors. | 307 | SH7366 and SH7723 processors. |
308 | |||
309 | config USB_WHCI_HCD | ||
310 | tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)" | ||
311 | depends on EXPERIMENTAL | ||
312 | depends on PCI && USB | ||
313 | select USB_WUSB | ||
314 | select UWB_WHCI | ||
315 | help | ||
316 | A driver for PCI-based Wireless USB Host Controllers that are | ||
317 | compliant with the WHCI specification. | ||
318 | |||
319 | To compile this driver a module, choose M here: the module | ||
320 | will be called "whci-hcd". | ||
321 | |||
322 | config USB_HWA_HCD | ||
323 | tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)" | ||
324 | depends on EXPERIMENTAL | ||
325 | depends on USB | ||
326 | select USB_WUSB | ||
327 | select UWB_HWA | ||
328 | help | ||
329 | This driver enables you to connect Wireless USB devices to | ||
330 | your system using a Host Wire Adaptor USB dongle. This is an | ||
331 | UWB Radio Controller and WUSB Host Controller connected to | ||
332 | your machine via USB (specified in WUSB1.0). | ||
333 | |||
334 | To compile this driver a module, choose M here: the module | ||
335 | will be called "hwa-hc". | ||
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index f1edda2dcfde..23be22224044 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -8,6 +8,8 @@ endif | |||
8 | 8 | ||
9 | isp1760-objs := isp1760-hcd.o isp1760-if.o | 9 | isp1760-objs := isp1760-hcd.o isp1760-if.o |
10 | 10 | ||
11 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ | ||
12 | |||
11 | obj-$(CONFIG_PCI) += pci-quirks.o | 13 | obj-$(CONFIG_PCI) += pci-quirks.o |
12 | 14 | ||
13 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o | 15 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o |
@@ -19,3 +21,4 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | |||
19 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | 21 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o |
20 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o | 22 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o |
21 | obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o | 23 | obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o |
24 | obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o | ||
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c new file mode 100644 index 000000000000..64be4d88df11 --- /dev/null +++ b/drivers/usb/host/hwa-hc.c | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | * Host Wire Adapter: | ||
3 | * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * The HWA driver is a simple layer that forwards requests to the WAHC | ||
24 | * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host | ||
25 | * Controller) layers. | ||
26 | * | ||
27 | * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB | ||
28 | * Host Controller that is connected to your system via USB (a USB | ||
29 | * dongle that implements a USB host...). There is also a Device Wired | ||
30 | * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for | ||
31 | * transferring data (it is after all a USB host connected via | ||
32 | * Wireless USB), we have a common layer called Wire Adapter Host | ||
33 | * Controller that does all the hard work. The WUSBHC (Wireless USB | ||
34 | * Host Controller) is the part common to WUSB Host Controllers, the | ||
35 | * HWA and the PCI-based one, that is implemented following the WHCI | ||
36 | * spec. All these layers are implemented in ../wusbcore. | ||
37 | * | ||
38 | * The main functions are hwahc_op_urb_{en,de}queue(), that pass the | ||
39 | * job of converting a URB to a Wire Adapter | ||
40 | * | ||
41 | * Entry points: | ||
42 | * | ||
43 | * hwahc_driver_*() Driver initialization, registration and | ||
44 | * teardown. | ||
45 | * | ||
46 | * hwahc_probe() New device came up, create an instance for | ||
47 | * it [from device enumeration]. | ||
48 | * | ||
49 | * hwahc_disconnect() Remove device instance [from device | ||
50 | * enumeration]. | ||
51 | * | ||
52 | * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for | ||
53 | * starting/stopping/etc (some might be made also | ||
54 | * DWA). | ||
55 | */ | ||
56 | #include <linux/kernel.h> | ||
57 | #include <linux/version.h> | ||
58 | #include <linux/init.h> | ||
59 | #include <linux/module.h> | ||
60 | #include <linux/workqueue.h> | ||
61 | #include <linux/wait.h> | ||
62 | #include <linux/completion.h> | ||
63 | #include "../wusbcore/wa-hc.h" | ||
64 | #include "../wusbcore/wusbhc.h" | ||
65 | |||
66 | #define D_LOCAL 0 | ||
67 | #include <linux/uwb/debug.h> | ||
68 | |||
69 | struct hwahc { | ||
70 | struct wusbhc wusbhc; /* has to be 1st */ | ||
71 | struct wahc wa; | ||
72 | u8 buffer[16]; /* for misc usb transactions */ | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * FIXME should be wusbhc | ||
77 | * | ||
78 | * NOTE: we need to cache the Cluster ID because later...there is no | ||
79 | * way to get it :) | ||
80 | */ | ||
81 | static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id) | ||
82 | { | ||
83 | int result; | ||
84 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
85 | struct wahc *wa = &hwahc->wa; | ||
86 | struct device *dev = &wa->usb_iface->dev; | ||
87 | |||
88 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
89 | WUSB_REQ_SET_CLUSTER_ID, | ||
90 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
91 | cluster_id, | ||
92 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
93 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
94 | if (result < 0) | ||
95 | dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n", | ||
96 | cluster_id, result); | ||
97 | else | ||
98 | wusbhc->cluster_id = cluster_id; | ||
99 | dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id); | ||
100 | return result; | ||
101 | } | ||
102 | |||
103 | static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) | ||
104 | { | ||
105 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
106 | struct wahc *wa = &hwahc->wa; | ||
107 | |||
108 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
109 | WUSB_REQ_SET_NUM_DNTS, | ||
110 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
111 | interval << 8 | slots, | ||
112 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
113 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Reset a WUSB host controller and wait for it to complete doing it. | ||
118 | * | ||
119 | * @usb_hcd: Pointer to WUSB Host Controller instance. | ||
120 | * | ||
121 | */ | ||
122 | static int hwahc_op_reset(struct usb_hcd *usb_hcd) | ||
123 | { | ||
124 | int result; | ||
125 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
126 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
127 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
128 | |||
129 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
130 | mutex_lock(&wusbhc->mutex); | ||
131 | wa_nep_disarm(&hwahc->wa); | ||
132 | result = __wa_set_feature(&hwahc->wa, WA_RESET); | ||
133 | if (result < 0) { | ||
134 | dev_err(dev, "error commanding HC to reset: %d\n", result); | ||
135 | goto error_unlock; | ||
136 | } | ||
137 | d_printf(3, dev, "reset: waiting for device to change state\n"); | ||
138 | result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0); | ||
139 | if (result < 0) { | ||
140 | dev_err(dev, "error waiting for HC to reset: %d\n", result); | ||
141 | goto error_unlock; | ||
142 | } | ||
143 | error_unlock: | ||
144 | mutex_unlock(&wusbhc->mutex); | ||
145 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
146 | return result; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * FIXME: break this function up | ||
151 | */ | ||
152 | static int hwahc_op_start(struct usb_hcd *usb_hcd) | ||
153 | { | ||
154 | u8 addr; | ||
155 | int result; | ||
156 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
157 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
158 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
159 | |||
160 | /* Set up a Host Info WUSB Information Element */ | ||
161 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
162 | result = -ENOSPC; | ||
163 | mutex_lock(&wusbhc->mutex); | ||
164 | /* Start the numbering from the top so that the bottom | ||
165 | * range of the unauth addr space is used for devices, | ||
166 | * the top for HCs; use 0xfe - RC# */ | ||
167 | addr = wusb_cluster_id_get(); | ||
168 | if (addr == 0) | ||
169 | goto error_cluster_id_get; | ||
170 | result = __hwahc_set_cluster_id(hwahc, addr); | ||
171 | if (result < 0) | ||
172 | goto error_set_cluster_id; | ||
173 | |||
174 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
175 | if (result < 0) { | ||
176 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
177 | goto error_stop; | ||
178 | } | ||
179 | usb_hcd->uses_new_polling = 1; | ||
180 | usb_hcd->poll_rh = 1; | ||
181 | usb_hcd->state = HC_STATE_RUNNING; | ||
182 | result = 0; | ||
183 | out: | ||
184 | mutex_unlock(&wusbhc->mutex); | ||
185 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
186 | return result; | ||
187 | |||
188 | error_stop: | ||
189 | __wa_stop(&hwahc->wa); | ||
190 | error_set_cluster_id: | ||
191 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
192 | error_cluster_id_get: | ||
193 | goto out; | ||
194 | |||
195 | } | ||
196 | |||
197 | /* | ||
198 | * FIXME: break this function up | ||
199 | */ | ||
200 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
201 | { | ||
202 | int result; | ||
203 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
204 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
205 | |||
206 | /* Set up a Host Info WUSB Information Element */ | ||
207 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
208 | result = -ENOSPC; | ||
209 | |||
210 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
211 | if (result < 0) { | ||
212 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
213 | goto error_stop; | ||
214 | } | ||
215 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
216 | if (result < 0) { | ||
217 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
218 | goto error_stop; | ||
219 | } | ||
220 | result = 0; | ||
221 | out: | ||
222 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
223 | return result; | ||
224 | |||
225 | error_stop: | ||
226 | result = __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) | ||
231 | { | ||
232 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
233 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
234 | dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__, | ||
235 | usb_hcd, hwahc, *(unsigned long *) &msg); | ||
236 | return -ENOSYS; | ||
237 | } | ||
238 | |||
239 | static int hwahc_op_resume(struct usb_hcd *usb_hcd) | ||
240 | { | ||
241 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
242 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
243 | |||
244 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
245 | usb_hcd, hwahc); | ||
246 | return -ENOSYS; | ||
247 | } | ||
248 | |||
249 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc) | ||
250 | { | ||
251 | int result; | ||
252 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
253 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
254 | |||
255 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
256 | /* Nothing for now */ | ||
257 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * No need to abort pipes, as when this is called, all the children | ||
263 | * has been disconnected and that has done it [through | ||
264 | * usb_disable_interface() -> usb_disable_endpoint() -> | ||
265 | * hwahc_op_ep_disable() - >rpipe_ep_disable()]. | ||
266 | */ | ||
267 | static void hwahc_op_stop(struct usb_hcd *usb_hcd) | ||
268 | { | ||
269 | int result; | ||
270 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
271 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
272 | struct wahc *wa = &hwahc->wa; | ||
273 | struct device *dev = &wa->usb_iface->dev; | ||
274 | |||
275 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
276 | mutex_lock(&wusbhc->mutex); | ||
277 | wusbhc_stop(wusbhc); | ||
278 | wa_nep_disarm(&hwahc->wa); | ||
279 | result = __wa_stop(&hwahc->wa); | ||
280 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
281 | mutex_unlock(&wusbhc->mutex); | ||
282 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd) | ||
287 | { | ||
288 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
289 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
290 | |||
291 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
292 | usb_hcd, hwahc); | ||
293 | return -ENOSYS; | ||
294 | } | ||
295 | |||
296 | static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
297 | gfp_t gfp) | ||
298 | { | ||
299 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
300 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
301 | |||
302 | return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp); | ||
303 | } | ||
304 | |||
305 | static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
306 | int status) | ||
307 | { | ||
308 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
309 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
310 | |||
311 | return wa_urb_dequeue(&hwahc->wa, urb); | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * Release resources allocated for an endpoint | ||
316 | * | ||
317 | * If there is an associated rpipe to this endpoint, go ahead and put it. | ||
318 | */ | ||
319 | static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, | ||
320 | struct usb_host_endpoint *ep) | ||
321 | { | ||
322 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
323 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
324 | |||
325 | rpipe_ep_disable(&hwahc->wa, ep); | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Set the UWB MAS allocation for the WUSB cluster | ||
330 | * | ||
331 | * @stream_index: stream to use (-1 for cancelling the allocation) | ||
332 | * @mas: mas bitmap to use | ||
333 | */ | ||
334 | static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, | ||
335 | const struct uwb_mas_bm *mas) | ||
336 | { | ||
337 | int result; | ||
338 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
339 | struct wahc *wa = &hwahc->wa; | ||
340 | struct device *dev = &wa->usb_iface->dev; | ||
341 | u8 mas_le[UWB_NUM_MAS/8]; | ||
342 | |||
343 | /* Set the stream index */ | ||
344 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
345 | WUSB_REQ_SET_STREAM_IDX, | ||
346 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
347 | stream_index, | ||
348 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
349 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
350 | if (result < 0) { | ||
351 | dev_err(dev, "Cannot set WUSB stream index: %d\n", result); | ||
352 | goto out; | ||
353 | } | ||
354 | uwb_mas_bm_copy_le(mas_le, mas); | ||
355 | /* Set the MAS allocation */ | ||
356 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
357 | WUSB_REQ_SET_WUSB_MAS, | ||
358 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
360 | mas_le, 32, 1000 /* FIXME: arbitrary */); | ||
361 | if (result < 0) | ||
362 | dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result); | ||
363 | out: | ||
364 | return result; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Add an IE to the host's MMC | ||
369 | * | ||
370 | * @interval: See WUSB1.0[8.5.3.1] | ||
371 | * @repeat_cnt: See WUSB1.0[8.5.3.1] | ||
372 | * @handle: See WUSB1.0[8.5.3.1] | ||
373 | * @wuie: Pointer to the header of the WUSB IE data to add. | ||
374 | * MUST BE allocated in a kmalloc buffer (no stack or | ||
375 | * vmalloc). | ||
376 | * | ||
377 | * NOTE: the format of the WUSB IEs for MMCs are different to the | ||
378 | * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length + | ||
379 | * Id in WUSB IEs). Standards...you gotta love'em. | ||
380 | */ | ||
381 | static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval, | ||
382 | u8 repeat_cnt, u8 handle, | ||
383 | struct wuie_hdr *wuie) | ||
384 | { | ||
385 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
386 | struct wahc *wa = &hwahc->wa; | ||
387 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
388 | |||
389 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
390 | WUSB_REQ_ADD_MMC_IE, | ||
391 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
392 | interval << 8 | repeat_cnt, | ||
393 | handle << 8 | iface_no, | ||
394 | wuie, wuie->bLength, 1000 /* FIXME: arbitrary */); | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * Remove an IE to the host's MMC | ||
399 | * | ||
400 | * @handle: See WUSB1.0[8.5.3.1] | ||
401 | */ | ||
402 | static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle) | ||
403 | { | ||
404 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
405 | struct wahc *wa = &hwahc->wa; | ||
406 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
407 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
408 | WUSB_REQ_REMOVE_MMC_IE, | ||
409 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
410 | 0, handle << 8 | iface_no, | ||
411 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * Update device information for a given fake port | ||
416 | * | ||
417 | * @port_idx: Fake port to which device is connected (wusbhc index, not | ||
418 | * USB port number). | ||
419 | */ | ||
420 | static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc, | ||
421 | struct wusb_dev *wusb_dev) | ||
422 | { | ||
423 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
424 | struct wahc *wa = &hwahc->wa; | ||
425 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
426 | struct hwa_dev_info *dev_info; | ||
427 | int ret; | ||
428 | |||
429 | /* fill out the Device Info buffer and send it */ | ||
430 | dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL); | ||
431 | if (!dev_info) | ||
432 | return -ENOMEM; | ||
433 | uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability, | ||
434 | &wusb_dev->availability); | ||
435 | dev_info->bDeviceAddress = wusb_dev->addr; | ||
436 | |||
437 | /* | ||
438 | * If the descriptors haven't been read yet, use a default PHY | ||
439 | * rate of 53.3 Mbit/s only. The correct value will be used | ||
440 | * when this will be called again as part of the | ||
441 | * authentication process (which occurs after the descriptors | ||
442 | * have been read). | ||
443 | */ | ||
444 | if (wusb_dev->wusb_cap_descr) | ||
445 | dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates; | ||
446 | else | ||
447 | dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53); | ||
448 | |||
449 | ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
450 | WUSB_REQ_SET_DEV_INFO, | ||
451 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
452 | 0, wusb_dev->port_idx << 8 | iface_no, | ||
453 | dev_info, sizeof(struct hwa_dev_info), | ||
454 | 1000 /* FIXME: arbitrary */); | ||
455 | kfree(dev_info); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Set host's idea of which encryption (and key) method to use when | ||
461 | * talking to ad evice on a given port. | ||
462 | * | ||
463 | * If key is NULL, it means disable encryption for that "virtual port" | ||
464 | * (used when we disconnect). | ||
465 | */ | ||
466 | static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
467 | const void *key, size_t key_size, | ||
468 | u8 key_idx) | ||
469 | { | ||
470 | int result = -ENOMEM; | ||
471 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
472 | struct wahc *wa = &hwahc->wa; | ||
473 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
474 | struct usb_key_descriptor *keyd; | ||
475 | size_t keyd_len; | ||
476 | |||
477 | keyd_len = sizeof(*keyd) + key_size; | ||
478 | keyd = kzalloc(keyd_len, GFP_KERNEL); | ||
479 | if (keyd == NULL) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | keyd->bLength = keyd_len; | ||
483 | keyd->bDescriptorType = USB_DT_KEY; | ||
484 | keyd->tTKID[0] = (tkid >> 0) & 0xff; | ||
485 | keyd->tTKID[1] = (tkid >> 8) & 0xff; | ||
486 | keyd->tTKID[2] = (tkid >> 16) & 0xff; | ||
487 | memcpy(keyd->bKeyData, key, key_size); | ||
488 | |||
489 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
490 | USB_REQ_SET_DESCRIPTOR, | ||
491 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
492 | USB_DT_KEY << 8 | key_idx, | ||
493 | port_idx << 8 | iface_no, | ||
494 | keyd, keyd_len, 1000 /* FIXME: arbitrary */); | ||
495 | |||
496 | memset(keyd, 0, sizeof(*keyd)); /* clear keys etc. */ | ||
497 | kfree(keyd); | ||
498 | return result; | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * Set host's idea of which encryption (and key) method to use when | ||
503 | * talking to ad evice on a given port. | ||
504 | * | ||
505 | * If key is NULL, it means disable encryption for that "virtual port" | ||
506 | * (used when we disconnect). | ||
507 | */ | ||
508 | static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
509 | const void *key, size_t key_size) | ||
510 | { | ||
511 | int result = -ENOMEM; | ||
512 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
513 | struct wahc *wa = &hwahc->wa; | ||
514 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
515 | u8 encryption_value; | ||
516 | |||
517 | /* Tell the host which key to use to talk to the device */ | ||
518 | if (key) { | ||
519 | u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK, | ||
520 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
521 | |||
522 | result = __hwahc_dev_set_key(wusbhc, port_idx, tkid, | ||
523 | key, key_size, key_idx); | ||
524 | if (result < 0) | ||
525 | goto error_set_key; | ||
526 | encryption_value = wusbhc->ccm1_etd->bEncryptionValue; | ||
527 | } else { | ||
528 | /* FIXME: this should come from wusbhc->etd[UNSECURE].value */ | ||
529 | encryption_value = 0; | ||
530 | } | ||
531 | |||
532 | /* Set the encryption type for commmunicating with the device */ | ||
533 | result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
534 | USB_REQ_SET_ENCRYPTION, | ||
535 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
536 | encryption_value, port_idx << 8 | iface_no, | ||
537 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
538 | if (result < 0) | ||
539 | dev_err(wusbhc->dev, "Can't set host's WUSB encryption for " | ||
540 | "port index %u to %s (value %d): %d\n", port_idx, | ||
541 | wusb_et_name(wusbhc->ccm1_etd->bEncryptionType), | ||
542 | wusbhc->ccm1_etd->bEncryptionValue, result); | ||
543 | error_set_key: | ||
544 | return result; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Set host's GTK key | ||
549 | */ | ||
550 | static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
551 | const void *key, size_t key_size) | ||
552 | { | ||
553 | u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, | ||
554 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
555 | |||
556 | return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx); | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * Get the Wire Adapter class-specific descriptor | ||
561 | * | ||
562 | * NOTE: this descriptor comes with the big bundled configuration | ||
563 | * descriptor that includes the interfaces' and endpoints', so | ||
564 | * we just look for it in the cached copy kept by the USB stack. | ||
565 | * | ||
566 | * NOTE2: We convert LE fields to CPU order. | ||
567 | */ | ||
568 | static int wa_fill_descr(struct wahc *wa) | ||
569 | { | ||
570 | int result; | ||
571 | struct device *dev = &wa->usb_iface->dev; | ||
572 | char *itr; | ||
573 | struct usb_device *usb_dev = wa->usb_dev; | ||
574 | struct usb_descriptor_header *hdr; | ||
575 | struct usb_wa_descriptor *wa_descr; | ||
576 | size_t itr_size, actconfig_idx; | ||
577 | |||
578 | actconfig_idx = (usb_dev->actconfig - usb_dev->config) / | ||
579 | sizeof(usb_dev->config[0]); | ||
580 | itr = usb_dev->rawdescriptors[actconfig_idx]; | ||
581 | itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); | ||
582 | while (itr_size >= sizeof(*hdr)) { | ||
583 | hdr = (struct usb_descriptor_header *) itr; | ||
584 | d_printf(3, dev, "Extra device descriptor: " | ||
585 | "type %02x/%u bytes @ %zu (%zu left)\n", | ||
586 | hdr->bDescriptorType, hdr->bLength, | ||
587 | (itr - usb_dev->rawdescriptors[actconfig_idx]), | ||
588 | itr_size); | ||
589 | if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER) | ||
590 | goto found; | ||
591 | itr += hdr->bLength; | ||
592 | itr_size -= hdr->bLength; | ||
593 | } | ||
594 | dev_err(dev, "cannot find Wire Adapter Class descriptor\n"); | ||
595 | return -ENODEV; | ||
596 | |||
597 | found: | ||
598 | result = -EINVAL; | ||
599 | if (hdr->bLength > itr_size) { /* is it available? */ | ||
600 | dev_err(dev, "incomplete Wire Adapter Class descriptor " | ||
601 | "(%zu bytes left, %u needed)\n", | ||
602 | itr_size, hdr->bLength); | ||
603 | goto error; | ||
604 | } | ||
605 | if (hdr->bLength < sizeof(*wa->wa_descr)) { | ||
606 | dev_err(dev, "short Wire Adapter Class descriptor\n"); | ||
607 | goto error; | ||
608 | } | ||
609 | wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; | ||
610 | /* Make LE fields CPU order */ | ||
611 | wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); | ||
612 | wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); | ||
613 | wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); | ||
614 | if (wa_descr->bcdWAVersion > 0x0100) | ||
615 | dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", | ||
616 | wa_descr->bcdWAVersion & 0xff00 >> 8, | ||
617 | wa_descr->bcdWAVersion & 0x00ff); | ||
618 | result = 0; | ||
619 | error: | ||
620 | return result; | ||
621 | } | ||
622 | |||
623 | static struct hc_driver hwahc_hc_driver = { | ||
624 | .description = "hwa-hcd", | ||
625 | .product_desc = "Wireless USB HWA host controller", | ||
626 | .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), | ||
627 | .irq = NULL, /* FIXME */ | ||
628 | .flags = HCD_USB2, /* FIXME */ | ||
629 | .reset = hwahc_op_reset, | ||
630 | .start = hwahc_op_start, | ||
631 | .pci_suspend = hwahc_op_suspend, | ||
632 | .pci_resume = hwahc_op_resume, | ||
633 | .stop = hwahc_op_stop, | ||
634 | .get_frame_number = hwahc_op_get_frame_number, | ||
635 | .urb_enqueue = hwahc_op_urb_enqueue, | ||
636 | .urb_dequeue = hwahc_op_urb_dequeue, | ||
637 | .endpoint_disable = hwahc_op_endpoint_disable, | ||
638 | |||
639 | .hub_status_data = wusbhc_rh_status_data, | ||
640 | .hub_control = wusbhc_rh_control, | ||
641 | .bus_suspend = wusbhc_rh_suspend, | ||
642 | .bus_resume = wusbhc_rh_resume, | ||
643 | .start_port_reset = wusbhc_rh_start_port_reset, | ||
644 | }; | ||
645 | |||
646 | static int hwahc_security_create(struct hwahc *hwahc) | ||
647 | { | ||
648 | int result; | ||
649 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
650 | struct usb_device *usb_dev = hwahc->wa.usb_dev; | ||
651 | struct device *dev = &usb_dev->dev; | ||
652 | struct usb_security_descriptor *secd; | ||
653 | struct usb_encryption_descriptor *etd; | ||
654 | void *itr, *top; | ||
655 | size_t itr_size, needed, bytes; | ||
656 | u8 index; | ||
657 | char buf[64]; | ||
658 | |||
659 | /* Find the host's security descriptors in the config descr bundle */ | ||
660 | index = (usb_dev->actconfig - usb_dev->config) / | ||
661 | sizeof(usb_dev->config[0]); | ||
662 | itr = usb_dev->rawdescriptors[index]; | ||
663 | itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); | ||
664 | top = itr + itr_size; | ||
665 | result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index], | ||
666 | le16_to_cpu(usb_dev->actconfig->desc.wTotalLength), | ||
667 | USB_DT_SECURITY, (void **) &secd); | ||
668 | if (result == -1) { | ||
669 | dev_warn(dev, "BUG? WUSB host has no security descriptors\n"); | ||
670 | return 0; | ||
671 | } | ||
672 | needed = sizeof(*secd); | ||
673 | if (top - (void *)secd < needed) { | ||
674 | dev_err(dev, "BUG? Not enough data to process security " | ||
675 | "descriptor header (%zu bytes left vs %zu needed)\n", | ||
676 | top - (void *) secd, needed); | ||
677 | return 0; | ||
678 | } | ||
679 | needed = le16_to_cpu(secd->wTotalLength); | ||
680 | if (top - (void *)secd < needed) { | ||
681 | dev_err(dev, "BUG? Not enough data to process security " | ||
682 | "descriptors (%zu bytes left vs %zu needed)\n", | ||
683 | top - (void *) secd, needed); | ||
684 | return 0; | ||
685 | } | ||
686 | /* Walk over the sec descriptors and store CCM1's on wusbhc */ | ||
687 | itr = (void *) secd + sizeof(*secd); | ||
688 | top = (void *) secd + le16_to_cpu(secd->wTotalLength); | ||
689 | index = 0; | ||
690 | bytes = 0; | ||
691 | while (itr < top) { | ||
692 | etd = itr; | ||
693 | if (top - itr < sizeof(*etd)) { | ||
694 | dev_err(dev, "BUG: bad host security descriptor; " | ||
695 | "not enough data (%zu vs %zu left)\n", | ||
696 | top - itr, sizeof(*etd)); | ||
697 | break; | ||
698 | } | ||
699 | if (etd->bLength < sizeof(*etd)) { | ||
700 | dev_err(dev, "BUG: bad host encryption descriptor; " | ||
701 | "descriptor is too short " | ||
702 | "(%zu vs %zu needed)\n", | ||
703 | (size_t)etd->bLength, sizeof(*etd)); | ||
704 | break; | ||
705 | } | ||
706 | itr += etd->bLength; | ||
707 | bytes += snprintf(buf + bytes, sizeof(buf) - bytes, | ||
708 | "%s (0x%02x) ", | ||
709 | wusb_et_name(etd->bEncryptionType), | ||
710 | etd->bEncryptionValue); | ||
711 | wusbhc->ccm1_etd = etd; | ||
712 | } | ||
713 | dev_info(dev, "supported encryption types: %s\n", buf); | ||
714 | if (wusbhc->ccm1_etd == NULL) { | ||
715 | dev_err(dev, "E: host doesn't support CCM-1 crypto\n"); | ||
716 | return 0; | ||
717 | } | ||
718 | /* Pretty print what we support */ | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static void hwahc_security_release(struct hwahc *hwahc) | ||
723 | { | ||
724 | /* nothing to do here so far... */ | ||
725 | } | ||
726 | |||
727 | static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) | ||
728 | { | ||
729 | int result; | ||
730 | struct device *dev = &iface->dev; | ||
731 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
732 | struct wahc *wa = &hwahc->wa; | ||
733 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
734 | |||
735 | wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ | ||
736 | wa->usb_iface = usb_get_intf(iface); | ||
737 | wusbhc->dev = dev; | ||
738 | wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent); | ||
739 | if (wusbhc->uwb_rc == NULL) { | ||
740 | result = -ENODEV; | ||
741 | dev_err(dev, "Cannot get associated UWB Host Controller\n"); | ||
742 | goto error_rc_get; | ||
743 | } | ||
744 | result = wa_fill_descr(wa); /* Get the device descriptor */ | ||
745 | if (result < 0) | ||
746 | goto error_fill_descriptor; | ||
747 | if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) { | ||
748 | dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB " | ||
749 | "adapter (%u ports)\n", wa->wa_descr->bNumPorts); | ||
750 | wusbhc->ports_max = USB_MAXCHILDREN; | ||
751 | } else { | ||
752 | wusbhc->ports_max = wa->wa_descr->bNumPorts; | ||
753 | } | ||
754 | wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs; | ||
755 | wusbhc->start = __hwahc_op_wusbhc_start; | ||
756 | wusbhc->stop = __hwahc_op_wusbhc_stop; | ||
757 | wusbhc->mmcie_add = __hwahc_op_mmcie_add; | ||
758 | wusbhc->mmcie_rm = __hwahc_op_mmcie_rm; | ||
759 | wusbhc->dev_info_set = __hwahc_op_dev_info_set; | ||
760 | wusbhc->bwa_set = __hwahc_op_bwa_set; | ||
761 | wusbhc->set_num_dnts = __hwahc_op_set_num_dnts; | ||
762 | wusbhc->set_ptk = __hwahc_op_set_ptk; | ||
763 | wusbhc->set_gtk = __hwahc_op_set_gtk; | ||
764 | result = hwahc_security_create(hwahc); | ||
765 | if (result < 0) { | ||
766 | dev_err(dev, "Can't initialize security: %d\n", result); | ||
767 | goto error_security_create; | ||
768 | } | ||
769 | wa->wusb = wusbhc; /* FIXME: ugly, need to fix */ | ||
770 | result = wusbhc_create(&hwahc->wusbhc); | ||
771 | if (result < 0) { | ||
772 | dev_err(dev, "Can't create WUSB HC structures: %d\n", result); | ||
773 | goto error_wusbhc_create; | ||
774 | } | ||
775 | result = wa_create(&hwahc->wa, iface); | ||
776 | if (result < 0) | ||
777 | goto error_wa_create; | ||
778 | return 0; | ||
779 | |||
780 | error_wa_create: | ||
781 | wusbhc_destroy(&hwahc->wusbhc); | ||
782 | error_wusbhc_create: | ||
783 | /* WA Descr fill allocs no resources */ | ||
784 | error_security_create: | ||
785 | error_fill_descriptor: | ||
786 | uwb_rc_put(wusbhc->uwb_rc); | ||
787 | error_rc_get: | ||
788 | usb_put_intf(iface); | ||
789 | usb_put_dev(usb_dev); | ||
790 | return result; | ||
791 | } | ||
792 | |||
793 | static void hwahc_destroy(struct hwahc *hwahc) | ||
794 | { | ||
795 | struct wusbhc *wusbhc = &hwahc->wusbhc; | ||
796 | |||
797 | d_fnstart(1, NULL, "(hwahc %p)\n", hwahc); | ||
798 | mutex_lock(&wusbhc->mutex); | ||
799 | __wa_destroy(&hwahc->wa); | ||
800 | wusbhc_destroy(&hwahc->wusbhc); | ||
801 | hwahc_security_release(hwahc); | ||
802 | hwahc->wusbhc.dev = NULL; | ||
803 | uwb_rc_put(wusbhc->uwb_rc); | ||
804 | usb_put_intf(hwahc->wa.usb_iface); | ||
805 | usb_put_dev(hwahc->wa.usb_dev); | ||
806 | mutex_unlock(&wusbhc->mutex); | ||
807 | d_fnend(1, NULL, "(hwahc %p) = void\n", hwahc); | ||
808 | } | ||
809 | |||
810 | static void hwahc_init(struct hwahc *hwahc) | ||
811 | { | ||
812 | wa_init(&hwahc->wa); | ||
813 | } | ||
814 | |||
815 | static int hwahc_probe(struct usb_interface *usb_iface, | ||
816 | const struct usb_device_id *id) | ||
817 | { | ||
818 | int result; | ||
819 | struct usb_hcd *usb_hcd; | ||
820 | struct wusbhc *wusbhc; | ||
821 | struct hwahc *hwahc; | ||
822 | struct device *dev = &usb_iface->dev; | ||
823 | |||
824 | d_fnstart(4, dev, "(%p, %p)\n", usb_iface, id); | ||
825 | result = -ENOMEM; | ||
826 | usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa"); | ||
827 | if (usb_hcd == NULL) { | ||
828 | dev_err(dev, "unable to allocate instance\n"); | ||
829 | goto error_alloc; | ||
830 | } | ||
831 | usb_hcd->wireless = 1; | ||
832 | usb_hcd->flags |= HCD_FLAG_SAW_IRQ; | ||
833 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
834 | hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
835 | hwahc_init(hwahc); | ||
836 | result = hwahc_create(hwahc, usb_iface); | ||
837 | if (result < 0) { | ||
838 | dev_err(dev, "Cannot initialize internals: %d\n", result); | ||
839 | goto error_hwahc_create; | ||
840 | } | ||
841 | result = usb_add_hcd(usb_hcd, 0, 0); | ||
842 | if (result < 0) { | ||
843 | dev_err(dev, "Cannot add HCD: %d\n", result); | ||
844 | goto error_add_hcd; | ||
845 | } | ||
846 | result = wusbhc_b_create(&hwahc->wusbhc); | ||
847 | if (result < 0) { | ||
848 | dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); | ||
849 | goto error_wusbhc_b_create; | ||
850 | } | ||
851 | d_fnend(4, dev, "(%p, %p) = 0\n", usb_iface, id); | ||
852 | return 0; | ||
853 | |||
854 | error_wusbhc_b_create: | ||
855 | usb_remove_hcd(usb_hcd); | ||
856 | error_add_hcd: | ||
857 | hwahc_destroy(hwahc); | ||
858 | error_hwahc_create: | ||
859 | usb_put_hcd(usb_hcd); | ||
860 | error_alloc: | ||
861 | d_fnend(4, dev, "(%p, %p) = %d\n", usb_iface, id, result); | ||
862 | return result; | ||
863 | } | ||
864 | |||
865 | static void hwahc_disconnect(struct usb_interface *usb_iface) | ||
866 | { | ||
867 | struct usb_hcd *usb_hcd; | ||
868 | struct wusbhc *wusbhc; | ||
869 | struct hwahc *hwahc; | ||
870 | |||
871 | usb_hcd = usb_get_intfdata(usb_iface); | ||
872 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
873 | hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
874 | |||
875 | d_fnstart(1, NULL, "(hwahc %p [usb_iface %p])\n", hwahc, usb_iface); | ||
876 | wusbhc_b_destroy(&hwahc->wusbhc); | ||
877 | usb_remove_hcd(usb_hcd); | ||
878 | hwahc_destroy(hwahc); | ||
879 | usb_put_hcd(usb_hcd); | ||
880 | d_fnend(1, NULL, "(hwahc %p [usb_iface %p]) = void\n", hwahc, | ||
881 | usb_iface); | ||
882 | } | ||
883 | |||
884 | /** USB device ID's that we handle */ | ||
885 | static struct usb_device_id hwahc_id_table[] = { | ||
886 | /* FIXME: use class labels for this */ | ||
887 | { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, | ||
888 | {}, | ||
889 | }; | ||
890 | MODULE_DEVICE_TABLE(usb, hwahc_id_table); | ||
891 | |||
892 | static struct usb_driver hwahc_driver = { | ||
893 | .name = "hwa-hc", | ||
894 | .probe = hwahc_probe, | ||
895 | .disconnect = hwahc_disconnect, | ||
896 | .id_table = hwahc_id_table, | ||
897 | }; | ||
898 | |||
899 | static int __init hwahc_driver_init(void) | ||
900 | { | ||
901 | int result; | ||
902 | result = usb_register(&hwahc_driver); | ||
903 | if (result < 0) { | ||
904 | printk(KERN_ERR "WA-CDS: Cannot register USB driver: %d\n", | ||
905 | result); | ||
906 | goto error_usb_register; | ||
907 | } | ||
908 | return 0; | ||
909 | |||
910 | error_usb_register: | ||
911 | return result; | ||
912 | |||
913 | } | ||
914 | module_init(hwahc_driver_init); | ||
915 | |||
916 | static void __exit hwahc_driver_exit(void) | ||
917 | { | ||
918 | usb_deregister(&hwahc_driver); | ||
919 | } | ||
920 | module_exit(hwahc_driver_exit); | ||
921 | |||
922 | |||
923 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
924 | MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver"); | ||
925 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild new file mode 100644 index 000000000000..26a3871ea0f9 --- /dev/null +++ b/drivers/usb/host/whci/Kbuild | |||
@@ -0,0 +1,11 @@ | |||
1 | obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o | ||
2 | |||
3 | whci-hcd-y := \ | ||
4 | asl.o \ | ||
5 | hcd.o \ | ||
6 | hw.o \ | ||
7 | init.o \ | ||
8 | int.o \ | ||
9 | pzl.o \ | ||
10 | qset.o \ | ||
11 | wusb.o | ||
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c new file mode 100644 index 000000000000..4d7078e50572 --- /dev/null +++ b/drivers/usb/host/whci/asl.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) asynchronous schedule management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_asl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | |||
35 | d_printf(4, dev, "ASL %s\n", tag); | ||
36 | |||
37 | list_for_each_entry(qset, &whc->async_list, list_node) { | ||
38 | dump_qset(qset, dev); | ||
39 | } | ||
40 | } | ||
41 | #else | ||
42 | static inline void dump_asl(struct whc *whc, const char *tag) | ||
43 | { | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | |||
48 | static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, | ||
49 | struct whc_qset **next, struct whc_qset **prev) | ||
50 | { | ||
51 | struct list_head *n, *p; | ||
52 | |||
53 | BUG_ON(list_empty(&whc->async_list)); | ||
54 | |||
55 | n = qset->list_node.next; | ||
56 | if (n == &whc->async_list) | ||
57 | n = n->next; | ||
58 | p = qset->list_node.prev; | ||
59 | if (p == &whc->async_list) | ||
60 | p = p->prev; | ||
61 | |||
62 | *next = container_of(n, struct whc_qset, list_node); | ||
63 | *prev = container_of(p, struct whc_qset, list_node); | ||
64 | |||
65 | } | ||
66 | |||
67 | static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset) | ||
68 | { | ||
69 | list_move(&qset->list_node, &whc->async_list); | ||
70 | qset->in_sw_list = true; | ||
71 | } | ||
72 | |||
73 | static void asl_qset_insert(struct whc *whc, struct whc_qset *qset) | ||
74 | { | ||
75 | struct whc_qset *next, *prev; | ||
76 | |||
77 | qset_clear(whc, qset); | ||
78 | |||
79 | /* Link into ASL. */ | ||
80 | qset_get_next_prev(whc, qset, &next, &prev); | ||
81 | whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma); | ||
82 | whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma); | ||
83 | qset->in_hw_list = true; | ||
84 | } | ||
85 | |||
86 | static void asl_qset_remove(struct whc *whc, struct whc_qset *qset) | ||
87 | { | ||
88 | struct whc_qset *prev, *next; | ||
89 | |||
90 | qset_get_next_prev(whc, qset, &next, &prev); | ||
91 | |||
92 | list_move(&qset->list_node, &whc->async_removed_list); | ||
93 | qset->in_sw_list = false; | ||
94 | |||
95 | /* | ||
96 | * No more qsets in the ASL? The caller must stop the ASL as | ||
97 | * it's no longer valid. | ||
98 | */ | ||
99 | if (list_empty(&whc->async_list)) | ||
100 | return; | ||
101 | |||
102 | /* Remove from ASL. */ | ||
103 | whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma); | ||
104 | qset->in_hw_list = false; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * process_qset - process any recently inactivated or halted qTDs in a | ||
109 | * qset. | ||
110 | * | ||
111 | * After inactive qTDs are removed, new qTDs can be added if the | ||
112 | * urb queue still contains URBs. | ||
113 | * | ||
114 | * Returns any additional WUSBCMD bits for the ASL sync command (i.e., | ||
115 | * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed). | ||
116 | */ | ||
117 | static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) | ||
118 | { | ||
119 | enum whc_update update = 0; | ||
120 | uint32_t status = 0; | ||
121 | |||
122 | while (qset->ntds) { | ||
123 | struct whc_qtd *td; | ||
124 | int t; | ||
125 | |||
126 | t = qset->td_start; | ||
127 | td = &qset->qtd[qset->td_start]; | ||
128 | status = le32_to_cpu(td->status); | ||
129 | |||
130 | /* | ||
131 | * Nothing to do with a still active qTD. | ||
132 | */ | ||
133 | if (status & QTD_STS_ACTIVE) | ||
134 | break; | ||
135 | |||
136 | if (status & QTD_STS_HALTED) { | ||
137 | /* Ug, an error. */ | ||
138 | process_halted_qtd(whc, qset, td); | ||
139 | goto done; | ||
140 | } | ||
141 | |||
142 | /* Mmm, a completed qTD. */ | ||
143 | process_inactive_qtd(whc, qset, td); | ||
144 | } | ||
145 | |||
146 | update |= qset_add_qtds(whc, qset); | ||
147 | |||
148 | done: | ||
149 | /* | ||
150 | * Remove this qset from the ASL if requested, but only if has | ||
151 | * no qTDs. | ||
152 | */ | ||
153 | if (qset->remove && qset->ntds == 0) { | ||
154 | asl_qset_remove(whc, qset); | ||
155 | update |= WHC_UPDATE_REMOVED; | ||
156 | } | ||
157 | return update; | ||
158 | } | ||
159 | |||
160 | void asl_start(struct whc *whc) | ||
161 | { | ||
162 | struct whc_qset *qset; | ||
163 | |||
164 | qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); | ||
165 | |||
166 | le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR); | ||
167 | |||
168 | whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN); | ||
169 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
170 | WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED, | ||
171 | 1000, "start ASL"); | ||
172 | } | ||
173 | |||
174 | void asl_stop(struct whc *whc) | ||
175 | { | ||
176 | whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0); | ||
177 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
178 | WUSBSTS_ASYNC_SCHED, 0, | ||
179 | 1000, "stop ASL"); | ||
180 | } | ||
181 | |||
182 | void asl_update(struct whc *whc, uint32_t wusbcmd) | ||
183 | { | ||
184 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
185 | wait_event(whc->async_list_wq, | ||
186 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * scan_async_work - scan the ASL for qsets to process. | ||
191 | * | ||
192 | * Process each qset in the ASL in turn and then signal the WHC that | ||
193 | * the ASL has been updated. | ||
194 | * | ||
195 | * Then start, stop or update the asynchronous schedule as required. | ||
196 | */ | ||
197 | void scan_async_work(struct work_struct *work) | ||
198 | { | ||
199 | struct whc *whc = container_of(work, struct whc, async_work); | ||
200 | struct whc_qset *qset, *t; | ||
201 | enum whc_update update = 0; | ||
202 | |||
203 | spin_lock_irq(&whc->lock); | ||
204 | |||
205 | dump_asl(whc, "before processing"); | ||
206 | |||
207 | /* | ||
208 | * Transerve the software list backwards so new qsets can be | ||
209 | * safely inserted into the ASL without making it non-circular. | ||
210 | */ | ||
211 | list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) { | ||
212 | if (!qset->in_hw_list) { | ||
213 | asl_qset_insert(whc, qset); | ||
214 | update |= WHC_UPDATE_ADDED; | ||
215 | } | ||
216 | |||
217 | update |= process_qset(whc, qset); | ||
218 | } | ||
219 | |||
220 | dump_asl(whc, "after processing"); | ||
221 | |||
222 | spin_unlock_irq(&whc->lock); | ||
223 | |||
224 | if (update) { | ||
225 | uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB; | ||
226 | if (update & WHC_UPDATE_REMOVED) | ||
227 | wusbcmd |= WUSBCMD_ASYNC_QSET_RM; | ||
228 | asl_update(whc, wusbcmd); | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * Now that the ASL is updated, complete the removal of any | ||
233 | * removed qsets. | ||
234 | */ | ||
235 | spin_lock(&whc->lock); | ||
236 | |||
237 | list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { | ||
238 | qset_remove_complete(whc, qset); | ||
239 | } | ||
240 | |||
241 | spin_unlock(&whc->lock); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL). | ||
246 | * @whc: the WHCI host controller | ||
247 | * @urb: the URB to enqueue | ||
248 | * @mem_flags: flags for any memory allocations | ||
249 | * | ||
250 | * The qset for the endpoint is obtained and the urb queued on to it. | ||
251 | * | ||
252 | * Work is scheduled to update the hardware's view of the ASL. | ||
253 | */ | ||
254 | int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | ||
255 | { | ||
256 | struct whc_qset *qset; | ||
257 | int err; | ||
258 | unsigned long flags; | ||
259 | |||
260 | spin_lock_irqsave(&whc->lock, flags); | ||
261 | |||
262 | qset = get_qset(whc, urb, GFP_ATOMIC); | ||
263 | if (qset == NULL) | ||
264 | err = -ENOMEM; | ||
265 | else | ||
266 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | ||
267 | if (!err) { | ||
268 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
269 | if (!qset->in_sw_list) | ||
270 | asl_qset_insert_begin(whc, qset); | ||
271 | } | ||
272 | |||
273 | spin_unlock_irqrestore(&whc->lock, flags); | ||
274 | |||
275 | if (!err) | ||
276 | queue_work(whc->workqueue, &whc->async_work); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * asl_urb_dequeue - remove an URB (qset) from the async list. | ||
283 | * @whc: the WHCI host controller | ||
284 | * @urb: the URB to dequeue | ||
285 | * @status: the current status of the URB | ||
286 | * | ||
287 | * URBs that do yet have qTDs can simply be removed from the software | ||
288 | * queue, otherwise the qset must be removed from the ASL so the qTDs | ||
289 | * can be removed. | ||
290 | */ | ||
291 | int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) | ||
292 | { | ||
293 | struct whc_urb *wurb = urb->hcpriv; | ||
294 | struct whc_qset *qset = wurb->qset; | ||
295 | struct whc_std *std, *t; | ||
296 | int ret; | ||
297 | unsigned long flags; | ||
298 | |||
299 | spin_lock_irqsave(&whc->lock, flags); | ||
300 | |||
301 | ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); | ||
302 | if (ret < 0) | ||
303 | goto out; | ||
304 | |||
305 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
306 | if (std->urb == urb) | ||
307 | qset_free_std(whc, std); | ||
308 | else | ||
309 | std->qtd = NULL; /* so this std is re-added when the qset is */ | ||
310 | } | ||
311 | |||
312 | asl_qset_remove(whc, qset); | ||
313 | wurb->status = status; | ||
314 | wurb->is_async = true; | ||
315 | queue_work(whc->workqueue, &wurb->dequeue_work); | ||
316 | |||
317 | out: | ||
318 | spin_unlock_irqrestore(&whc->lock, flags); | ||
319 | |||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * asl_qset_delete - delete a qset from the ASL | ||
325 | */ | ||
326 | void asl_qset_delete(struct whc *whc, struct whc_qset *qset) | ||
327 | { | ||
328 | qset->remove = 1; | ||
329 | queue_work(whc->workqueue, &whc->async_work); | ||
330 | qset_delete(whc, qset); | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * asl_init - initialize the asynchronous schedule list | ||
335 | * | ||
336 | * A dummy qset with no qTDs is added to the ASL to simplify removing | ||
337 | * qsets (no need to stop the ASL when the last qset is removed). | ||
338 | */ | ||
339 | int asl_init(struct whc *whc) | ||
340 | { | ||
341 | struct whc_qset *qset; | ||
342 | |||
343 | qset = qset_alloc(whc, GFP_KERNEL); | ||
344 | if (qset == NULL) | ||
345 | return -ENOMEM; | ||
346 | |||
347 | asl_qset_insert_begin(whc, qset); | ||
348 | asl_qset_insert(whc, qset); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * asl_clean_up - free ASL resources | ||
355 | * | ||
356 | * The ASL is stopped and empty except for the dummy qset. | ||
357 | */ | ||
358 | void asl_clean_up(struct whc *whc) | ||
359 | { | ||
360 | struct whc_qset *qset; | ||
361 | |||
362 | if (!list_empty(&whc->async_list)) { | ||
363 | qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); | ||
364 | list_del(&qset->list_node); | ||
365 | qset_free(whc, qset); | ||
366 | } | ||
367 | } | ||
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c new file mode 100644 index 000000000000..ef3ad4dca945 --- /dev/null +++ b/drivers/usb/host/whci/hcd.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) driver. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | /* | ||
28 | * One time initialization. | ||
29 | * | ||
30 | * Nothing to do here. | ||
31 | */ | ||
32 | static int whc_reset(struct usb_hcd *usb_hcd) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Start the wireless host controller. | ||
39 | * | ||
40 | * Start device notification. | ||
41 | * | ||
42 | * Put hc into run state, set DNTS parameters. | ||
43 | */ | ||
44 | static int whc_start(struct usb_hcd *usb_hcd) | ||
45 | { | ||
46 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
47 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
48 | u8 bcid; | ||
49 | int ret; | ||
50 | |||
51 | mutex_lock(&wusbhc->mutex); | ||
52 | |||
53 | le_writel(WUSBINTR_GEN_CMD_DONE | ||
54 | | WUSBINTR_HOST_ERR | ||
55 | | WUSBINTR_ASYNC_SCHED_SYNCED | ||
56 | | WUSBINTR_DNTS_INT | ||
57 | | WUSBINTR_ERR_INT | ||
58 | | WUSBINTR_INT, | ||
59 | whc->base + WUSBINTR); | ||
60 | |||
61 | /* set cluster ID */ | ||
62 | bcid = wusb_cluster_id_get(); | ||
63 | ret = whc_set_cluster_id(whc, bcid); | ||
64 | if (ret < 0) | ||
65 | goto out; | ||
66 | wusbhc->cluster_id = bcid; | ||
67 | |||
68 | /* start HC */ | ||
69 | whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN); | ||
70 | |||
71 | usb_hcd->uses_new_polling = 1; | ||
72 | usb_hcd->poll_rh = 1; | ||
73 | usb_hcd->state = HC_STATE_RUNNING; | ||
74 | |||
75 | out: | ||
76 | mutex_unlock(&wusbhc->mutex); | ||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | |||
81 | /* | ||
82 | * Stop the wireless host controller. | ||
83 | * | ||
84 | * Stop device notification. | ||
85 | * | ||
86 | * Wait for pending transfer to stop? Put hc into stop state? | ||
87 | */ | ||
88 | static void whc_stop(struct usb_hcd *usb_hcd) | ||
89 | { | ||
90 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
91 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
92 | |||
93 | mutex_lock(&wusbhc->mutex); | ||
94 | |||
95 | wusbhc_stop(wusbhc); | ||
96 | |||
97 | /* stop HC */ | ||
98 | le_writel(0, whc->base + WUSBINTR); | ||
99 | whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); | ||
100 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
101 | WUSBSTS_HCHALTED, WUSBSTS_HCHALTED, | ||
102 | 100, "HC to halt"); | ||
103 | |||
104 | wusb_cluster_id_put(wusbhc->cluster_id); | ||
105 | |||
106 | mutex_unlock(&wusbhc->mutex); | ||
107 | } | ||
108 | |||
109 | static int whc_get_frame_number(struct usb_hcd *usb_hcd) | ||
110 | { | ||
111 | /* Frame numbers are not applicable to WUSB. */ | ||
112 | return -ENOSYS; | ||
113 | } | ||
114 | |||
115 | |||
116 | /* | ||
117 | * Queue an URB to the ASL or PZL | ||
118 | */ | ||
119 | static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, | ||
120 | gfp_t mem_flags) | ||
121 | { | ||
122 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
123 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
124 | int ret; | ||
125 | |||
126 | switch (usb_pipetype(urb->pipe)) { | ||
127 | case PIPE_INTERRUPT: | ||
128 | ret = pzl_urb_enqueue(whc, urb, mem_flags); | ||
129 | break; | ||
130 | case PIPE_ISOCHRONOUS: | ||
131 | dev_err(&whc->umc->dev, "isochronous transfers unsupported\n"); | ||
132 | ret = -ENOTSUPP; | ||
133 | break; | ||
134 | case PIPE_CONTROL: | ||
135 | case PIPE_BULK: | ||
136 | default: | ||
137 | ret = asl_urb_enqueue(whc, urb, mem_flags); | ||
138 | break; | ||
139 | }; | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Remove a queued URB from the ASL or PZL. | ||
146 | */ | ||
147 | static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status) | ||
148 | { | ||
149 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
150 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
151 | int ret; | ||
152 | |||
153 | switch (usb_pipetype(urb->pipe)) { | ||
154 | case PIPE_INTERRUPT: | ||
155 | ret = pzl_urb_dequeue(whc, urb, status); | ||
156 | break; | ||
157 | case PIPE_ISOCHRONOUS: | ||
158 | ret = -ENOTSUPP; | ||
159 | break; | ||
160 | case PIPE_CONTROL: | ||
161 | case PIPE_BULK: | ||
162 | default: | ||
163 | ret = asl_urb_dequeue(whc, urb, status); | ||
164 | break; | ||
165 | }; | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Wait for all URBs to the endpoint to be completed, then delete the | ||
172 | * qset. | ||
173 | */ | ||
174 | static void whc_endpoint_disable(struct usb_hcd *usb_hcd, | ||
175 | struct usb_host_endpoint *ep) | ||
176 | { | ||
177 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
178 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
179 | struct whc_qset *qset; | ||
180 | |||
181 | qset = ep->hcpriv; | ||
182 | if (qset) { | ||
183 | ep->hcpriv = NULL; | ||
184 | if (usb_endpoint_xfer_bulk(&ep->desc) | ||
185 | || usb_endpoint_xfer_control(&ep->desc)) | ||
186 | asl_qset_delete(whc, qset); | ||
187 | else | ||
188 | pzl_qset_delete(whc, qset); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static struct hc_driver whc_hc_driver = { | ||
193 | .description = "whci-hcd", | ||
194 | .product_desc = "Wireless host controller", | ||
195 | .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd), | ||
196 | .irq = whc_int_handler, | ||
197 | .flags = HCD_USB2, | ||
198 | |||
199 | .reset = whc_reset, | ||
200 | .start = whc_start, | ||
201 | .stop = whc_stop, | ||
202 | .get_frame_number = whc_get_frame_number, | ||
203 | .urb_enqueue = whc_urb_enqueue, | ||
204 | .urb_dequeue = whc_urb_dequeue, | ||
205 | .endpoint_disable = whc_endpoint_disable, | ||
206 | |||
207 | .hub_status_data = wusbhc_rh_status_data, | ||
208 | .hub_control = wusbhc_rh_control, | ||
209 | .bus_suspend = wusbhc_rh_suspend, | ||
210 | .bus_resume = wusbhc_rh_resume, | ||
211 | .start_port_reset = wusbhc_rh_start_port_reset, | ||
212 | }; | ||
213 | |||
214 | static int whc_probe(struct umc_dev *umc) | ||
215 | { | ||
216 | int ret = -ENOMEM; | ||
217 | struct usb_hcd *usb_hcd; | ||
218 | struct wusbhc *wusbhc = NULL; | ||
219 | struct whc *whc = NULL; | ||
220 | struct device *dev = &umc->dev; | ||
221 | |||
222 | usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci"); | ||
223 | if (usb_hcd == NULL) { | ||
224 | dev_err(dev, "unable to create hcd\n"); | ||
225 | goto error; | ||
226 | } | ||
227 | |||
228 | usb_hcd->wireless = 1; | ||
229 | |||
230 | wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
231 | whc = wusbhc_to_whc(wusbhc); | ||
232 | whc->umc = umc; | ||
233 | |||
234 | ret = whc_init(whc); | ||
235 | if (ret) | ||
236 | goto error; | ||
237 | |||
238 | wusbhc->dev = dev; | ||
239 | wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); | ||
240 | if (!wusbhc->uwb_rc) { | ||
241 | ret = -ENODEV; | ||
242 | dev_err(dev, "cannot get radio controller\n"); | ||
243 | goto error; | ||
244 | } | ||
245 | |||
246 | if (whc->n_devices > USB_MAXCHILDREN) { | ||
247 | dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n", | ||
248 | whc->n_devices); | ||
249 | wusbhc->ports_max = USB_MAXCHILDREN; | ||
250 | } else | ||
251 | wusbhc->ports_max = whc->n_devices; | ||
252 | wusbhc->mmcies_max = whc->n_mmc_ies; | ||
253 | wusbhc->start = whc_wusbhc_start; | ||
254 | wusbhc->stop = whc_wusbhc_stop; | ||
255 | wusbhc->mmcie_add = whc_mmcie_add; | ||
256 | wusbhc->mmcie_rm = whc_mmcie_rm; | ||
257 | wusbhc->dev_info_set = whc_dev_info_set; | ||
258 | wusbhc->bwa_set = whc_bwa_set; | ||
259 | wusbhc->set_num_dnts = whc_set_num_dnts; | ||
260 | wusbhc->set_ptk = whc_set_ptk; | ||
261 | wusbhc->set_gtk = whc_set_gtk; | ||
262 | |||
263 | ret = wusbhc_create(wusbhc); | ||
264 | if (ret) | ||
265 | goto error_wusbhc_create; | ||
266 | |||
267 | ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED); | ||
268 | if (ret) { | ||
269 | dev_err(dev, "cannot add HCD: %d\n", ret); | ||
270 | goto error_usb_add_hcd; | ||
271 | } | ||
272 | |||
273 | ret = wusbhc_b_create(wusbhc); | ||
274 | if (ret) { | ||
275 | dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret); | ||
276 | goto error_wusbhc_b_create; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | error_wusbhc_b_create: | ||
282 | usb_remove_hcd(usb_hcd); | ||
283 | error_usb_add_hcd: | ||
284 | wusbhc_destroy(wusbhc); | ||
285 | error_wusbhc_create: | ||
286 | uwb_rc_put(wusbhc->uwb_rc); | ||
287 | error: | ||
288 | whc_clean_up(whc); | ||
289 | if (usb_hcd) | ||
290 | usb_put_hcd(usb_hcd); | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | |||
295 | static void whc_remove(struct umc_dev *umc) | ||
296 | { | ||
297 | struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev); | ||
298 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
299 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
300 | |||
301 | if (usb_hcd) { | ||
302 | wusbhc_b_destroy(wusbhc); | ||
303 | usb_remove_hcd(usb_hcd); | ||
304 | wusbhc_destroy(wusbhc); | ||
305 | uwb_rc_put(wusbhc->uwb_rc); | ||
306 | whc_clean_up(whc); | ||
307 | usb_put_hcd(usb_hcd); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | static struct umc_driver whci_hc_driver = { | ||
312 | .name = "whci-hcd", | ||
313 | .cap_id = UMC_CAP_ID_WHCI_WUSB_HC, | ||
314 | .probe = whc_probe, | ||
315 | .remove = whc_remove, | ||
316 | }; | ||
317 | |||
318 | static int __init whci_hc_driver_init(void) | ||
319 | { | ||
320 | return umc_driver_register(&whci_hc_driver); | ||
321 | } | ||
322 | module_init(whci_hc_driver_init); | ||
323 | |||
324 | static void __exit whci_hc_driver_exit(void) | ||
325 | { | ||
326 | umc_driver_unregister(&whci_hc_driver); | ||
327 | } | ||
328 | module_exit(whci_hc_driver_exit); | ||
329 | |||
330 | /* PCI device ID's that we handle (so it gets loaded) */ | ||
331 | static struct pci_device_id whci_hcd_id_table[] = { | ||
332 | { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, | ||
333 | { /* empty last entry */ } | ||
334 | }; | ||
335 | MODULE_DEVICE_TABLE(pci, whci_hcd_id_table); | ||
336 | |||
337 | MODULE_DESCRIPTION("WHCI Wireless USB host controller driver"); | ||
338 | MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); | ||
339 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c new file mode 100644 index 000000000000..ac86e59c1225 --- /dev/null +++ b/drivers/usb/host/whci/hw.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) hardware access helpers. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | |||
22 | #include "../../wusbcore/wusbhc.h" | ||
23 | |||
24 | #include "whcd.h" | ||
25 | |||
26 | void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val) | ||
27 | { | ||
28 | unsigned long flags; | ||
29 | u32 cmd; | ||
30 | |||
31 | spin_lock_irqsave(&whc->lock, flags); | ||
32 | |||
33 | cmd = le_readl(whc->base + WUSBCMD); | ||
34 | cmd = (cmd & ~mask) | val; | ||
35 | le_writel(cmd, whc->base + WUSBCMD); | ||
36 | |||
37 | spin_unlock_irqrestore(&whc->lock, flags); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register | ||
42 | * @whc: the WHCI HC | ||
43 | * @cmd: command to start. | ||
44 | * @params: parameters for the command (the WUSBGENCMDPARAMS register value). | ||
45 | * @addr: pointer to any data for the command (may be NULL). | ||
46 | * @len: length of the data (if any). | ||
47 | */ | ||
48 | int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | dma_addr_t dma_addr; | ||
52 | int t; | ||
53 | |||
54 | mutex_lock(&whc->mutex); | ||
55 | |||
56 | /* Wait for previous command to complete. */ | ||
57 | t = wait_event_timeout(whc->cmd_wq, | ||
58 | (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0, | ||
59 | WHC_GENCMD_TIMEOUT_MS); | ||
60 | if (t == 0) { | ||
61 | dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", | ||
62 | le_readl(whc->base + WUSBGENCMDSTS), | ||
63 | le_readl(whc->base + WUSBGENCMDPARAMS)); | ||
64 | return -ETIMEDOUT; | ||
65 | } | ||
66 | |||
67 | if (addr) { | ||
68 | memcpy(whc->gen_cmd_buf, addr, len); | ||
69 | dma_addr = whc->gen_cmd_buf_dma; | ||
70 | } else | ||
71 | dma_addr = 0; | ||
72 | |||
73 | /* Poke registers to start cmd. */ | ||
74 | spin_lock_irqsave(&whc->lock, flags); | ||
75 | |||
76 | le_writel(params, whc->base + WUSBGENCMDPARAMS); | ||
77 | le_writeq(dma_addr, whc->base + WUSBGENADDR); | ||
78 | |||
79 | le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd, | ||
80 | whc->base + WUSBGENCMDSTS); | ||
81 | |||
82 | spin_unlock_irqrestore(&whc->lock, flags); | ||
83 | |||
84 | mutex_unlock(&whc->mutex); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c new file mode 100644 index 000000000000..34a783cb0133 --- /dev/null +++ b/drivers/usb/host/whci/init.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) initialization. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | |||
22 | #include "../../wusbcore/wusbhc.h" | ||
23 | |||
24 | #include "whcd.h" | ||
25 | |||
26 | /* | ||
27 | * Reset the host controller. | ||
28 | */ | ||
29 | static void whc_hw_reset(struct whc *whc) | ||
30 | { | ||
31 | le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD); | ||
32 | whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0, | ||
33 | 100, "reset"); | ||
34 | } | ||
35 | |||
36 | static void whc_hw_init_di_buf(struct whc *whc) | ||
37 | { | ||
38 | int d; | ||
39 | |||
40 | /* Disable all entries in the Device Information buffer. */ | ||
41 | for (d = 0; d < whc->n_devices; d++) | ||
42 | whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE; | ||
43 | |||
44 | le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR); | ||
45 | } | ||
46 | |||
47 | static void whc_hw_init_dn_buf(struct whc *whc) | ||
48 | { | ||
49 | /* Clear the Device Notification buffer to ensure the V (valid) | ||
50 | * bits are clear. */ | ||
51 | memset(whc->dn_buf, 0, 4096); | ||
52 | |||
53 | le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR); | ||
54 | } | ||
55 | |||
56 | int whc_init(struct whc *whc) | ||
57 | { | ||
58 | u32 whcsparams; | ||
59 | int ret, i; | ||
60 | resource_size_t start, len; | ||
61 | |||
62 | spin_lock_init(&whc->lock); | ||
63 | mutex_init(&whc->mutex); | ||
64 | init_waitqueue_head(&whc->cmd_wq); | ||
65 | init_waitqueue_head(&whc->async_list_wq); | ||
66 | init_waitqueue_head(&whc->periodic_list_wq); | ||
67 | whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev)); | ||
68 | if (whc->workqueue == NULL) { | ||
69 | ret = -ENOMEM; | ||
70 | goto error; | ||
71 | } | ||
72 | INIT_WORK(&whc->dn_work, whc_dn_work); | ||
73 | |||
74 | INIT_WORK(&whc->async_work, scan_async_work); | ||
75 | INIT_LIST_HEAD(&whc->async_list); | ||
76 | INIT_LIST_HEAD(&whc->async_removed_list); | ||
77 | |||
78 | INIT_WORK(&whc->periodic_work, scan_periodic_work); | ||
79 | for (i = 0; i < 5; i++) | ||
80 | INIT_LIST_HEAD(&whc->periodic_list[i]); | ||
81 | INIT_LIST_HEAD(&whc->periodic_removed_list); | ||
82 | |||
83 | /* Map HC registers. */ | ||
84 | start = whc->umc->resource.start; | ||
85 | len = whc->umc->resource.end - start + 1; | ||
86 | if (!request_mem_region(start, len, "whci-hc")) { | ||
87 | dev_err(&whc->umc->dev, "can't request HC region\n"); | ||
88 | ret = -EBUSY; | ||
89 | goto error; | ||
90 | } | ||
91 | whc->base_phys = start; | ||
92 | whc->base = ioremap(start, len); | ||
93 | if (!whc->base) { | ||
94 | dev_err(&whc->umc->dev, "ioremap\n"); | ||
95 | ret = -ENOMEM; | ||
96 | goto error; | ||
97 | } | ||
98 | |||
99 | whc_hw_reset(whc); | ||
100 | |||
101 | /* Read maximum number of devices, keys and MMC IEs. */ | ||
102 | whcsparams = le_readl(whc->base + WHCSPARAMS); | ||
103 | whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams); | ||
104 | whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams); | ||
105 | whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams); | ||
106 | |||
107 | dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n", | ||
108 | whc->n_devices, whc->n_keys, whc->n_mmc_ies); | ||
109 | |||
110 | whc->qset_pool = dma_pool_create("qset", &whc->umc->dev, | ||
111 | sizeof(struct whc_qset), 64, 0); | ||
112 | if (whc->qset_pool == NULL) { | ||
113 | ret = -ENOMEM; | ||
114 | goto error; | ||
115 | } | ||
116 | |||
117 | ret = asl_init(whc); | ||
118 | if (ret < 0) | ||
119 | goto error; | ||
120 | ret = pzl_init(whc); | ||
121 | if (ret < 0) | ||
122 | goto error; | ||
123 | |||
124 | /* Allocate and initialize a buffer for generic commands, the | ||
125 | Device Information buffer, and the Device Notification | ||
126 | buffer. */ | ||
127 | |||
128 | whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, | ||
129 | &whc->gen_cmd_buf_dma, GFP_KERNEL); | ||
130 | if (whc->gen_cmd_buf == NULL) { | ||
131 | ret = -ENOMEM; | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | whc->dn_buf = dma_alloc_coherent(&whc->umc->dev, | ||
136 | sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, | ||
137 | &whc->dn_buf_dma, GFP_KERNEL); | ||
138 | if (!whc->dn_buf) { | ||
139 | ret = -ENOMEM; | ||
140 | goto error; | ||
141 | } | ||
142 | whc_hw_init_dn_buf(whc); | ||
143 | |||
144 | whc->di_buf = dma_alloc_coherent(&whc->umc->dev, | ||
145 | sizeof(struct di_buf_entry) * whc->n_devices, | ||
146 | &whc->di_buf_dma, GFP_KERNEL); | ||
147 | if (!whc->di_buf) { | ||
148 | ret = -ENOMEM; | ||
149 | goto error; | ||
150 | } | ||
151 | whc_hw_init_di_buf(whc); | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | error: | ||
156 | whc_clean_up(whc); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | void whc_clean_up(struct whc *whc) | ||
161 | { | ||
162 | resource_size_t len; | ||
163 | |||
164 | if (whc->di_buf) | ||
165 | dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices, | ||
166 | whc->di_buf, whc->di_buf_dma); | ||
167 | if (whc->dn_buf) | ||
168 | dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, | ||
169 | whc->dn_buf, whc->dn_buf_dma); | ||
170 | if (whc->gen_cmd_buf) | ||
171 | dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, | ||
172 | whc->gen_cmd_buf, whc->gen_cmd_buf_dma); | ||
173 | |||
174 | pzl_clean_up(whc); | ||
175 | asl_clean_up(whc); | ||
176 | |||
177 | if (whc->qset_pool) | ||
178 | dma_pool_destroy(whc->qset_pool); | ||
179 | |||
180 | len = whc->umc->resource.end - whc->umc->resource.start + 1; | ||
181 | if (whc->base) | ||
182 | iounmap(whc->base); | ||
183 | if (whc->base_phys) | ||
184 | release_mem_region(whc->base_phys, len); | ||
185 | |||
186 | if (whc->workqueue) | ||
187 | destroy_workqueue(whc->workqueue); | ||
188 | } | ||
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c new file mode 100644 index 000000000000..fce01174aa9b --- /dev/null +++ b/drivers/usb/host/whci/int.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) interrupt handling. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | static void transfer_done(struct whc *whc) | ||
28 | { | ||
29 | queue_work(whc->workqueue, &whc->async_work); | ||
30 | queue_work(whc->workqueue, &whc->periodic_work); | ||
31 | } | ||
32 | |||
33 | irqreturn_t whc_int_handler(struct usb_hcd *hcd) | ||
34 | { | ||
35 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd); | ||
36 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
37 | u32 sts; | ||
38 | |||
39 | sts = le_readl(whc->base + WUSBSTS); | ||
40 | if (!(sts & WUSBSTS_INT_MASK)) | ||
41 | return IRQ_NONE; | ||
42 | le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS); | ||
43 | |||
44 | if (sts & WUSBSTS_GEN_CMD_DONE) | ||
45 | wake_up(&whc->cmd_wq); | ||
46 | |||
47 | if (sts & WUSBSTS_HOST_ERR) | ||
48 | dev_err(&whc->umc->dev, "FIXME: host system error\n"); | ||
49 | |||
50 | if (sts & WUSBSTS_ASYNC_SCHED_SYNCED) | ||
51 | wake_up(&whc->async_list_wq); | ||
52 | |||
53 | if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED) | ||
54 | wake_up(&whc->periodic_list_wq); | ||
55 | |||
56 | if (sts & WUSBSTS_DNTS_INT) | ||
57 | queue_work(whc->workqueue, &whc->dn_work); | ||
58 | |||
59 | /* | ||
60 | * A transfer completed (see [WHCI] section 4.7.1.2 for when | ||
61 | * this occurs). | ||
62 | */ | ||
63 | if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT)) | ||
64 | transfer_done(whc); | ||
65 | |||
66 | return IRQ_HANDLED; | ||
67 | } | ||
68 | |||
69 | static int process_dn_buf(struct whc *whc) | ||
70 | { | ||
71 | struct wusbhc *wusbhc = &whc->wusbhc; | ||
72 | struct dn_buf_entry *dn; | ||
73 | int processed = 0; | ||
74 | |||
75 | for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) { | ||
76 | if (dn->status & WHC_DN_STATUS_VALID) { | ||
77 | wusbhc_handle_dn(wusbhc, dn->src_addr, | ||
78 | (struct wusb_dn_hdr *)dn->dn_data, | ||
79 | dn->msg_size); | ||
80 | dn->status &= ~WHC_DN_STATUS_VALID; | ||
81 | processed++; | ||
82 | } | ||
83 | } | ||
84 | return processed; | ||
85 | } | ||
86 | |||
87 | void whc_dn_work(struct work_struct *work) | ||
88 | { | ||
89 | struct whc *whc = container_of(work, struct whc, dn_work); | ||
90 | int processed; | ||
91 | |||
92 | do { | ||
93 | processed = process_dn_buf(whc); | ||
94 | } while (processed); | ||
95 | } | ||
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c new file mode 100644 index 000000000000..8d62df0c330b --- /dev/null +++ b/drivers/usb/host/whci/pzl.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) periodic schedule management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_pzl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | int period = 0; | ||
35 | |||
36 | d_printf(4, dev, "PZL %s\n", tag); | ||
37 | |||
38 | for (period = 0; period < 5; period++) { | ||
39 | d_printf(4, dev, "Period %d\n", period); | ||
40 | list_for_each_entry(qset, &whc->periodic_list[period], list_node) { | ||
41 | dump_qset(qset, dev); | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | #else | ||
46 | static inline void dump_pzl(struct whc *whc, const char *tag) | ||
47 | { | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | static void update_pzl_pointers(struct whc *whc, int period, u64 addr) | ||
52 | { | ||
53 | switch (period) { | ||
54 | case 0: | ||
55 | whc_qset_set_link_ptr(&whc->pz_list[0], addr); | ||
56 | whc_qset_set_link_ptr(&whc->pz_list[2], addr); | ||
57 | whc_qset_set_link_ptr(&whc->pz_list[4], addr); | ||
58 | whc_qset_set_link_ptr(&whc->pz_list[6], addr); | ||
59 | whc_qset_set_link_ptr(&whc->pz_list[8], addr); | ||
60 | whc_qset_set_link_ptr(&whc->pz_list[10], addr); | ||
61 | whc_qset_set_link_ptr(&whc->pz_list[12], addr); | ||
62 | whc_qset_set_link_ptr(&whc->pz_list[14], addr); | ||
63 | break; | ||
64 | case 1: | ||
65 | whc_qset_set_link_ptr(&whc->pz_list[1], addr); | ||
66 | whc_qset_set_link_ptr(&whc->pz_list[5], addr); | ||
67 | whc_qset_set_link_ptr(&whc->pz_list[9], addr); | ||
68 | whc_qset_set_link_ptr(&whc->pz_list[13], addr); | ||
69 | break; | ||
70 | case 2: | ||
71 | whc_qset_set_link_ptr(&whc->pz_list[3], addr); | ||
72 | whc_qset_set_link_ptr(&whc->pz_list[11], addr); | ||
73 | break; | ||
74 | case 3: | ||
75 | whc_qset_set_link_ptr(&whc->pz_list[7], addr); | ||
76 | break; | ||
77 | case 4: | ||
78 | whc_qset_set_link_ptr(&whc->pz_list[15], addr); | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Return the 'period' to use for this qset. The minimum interval for | ||
85 | * the endpoint is used so whatever urbs are submitted the device is | ||
86 | * polled often enough. | ||
87 | */ | ||
88 | static int qset_get_period(struct whc *whc, struct whc_qset *qset) | ||
89 | { | ||
90 | uint8_t bInterval = qset->ep->desc.bInterval; | ||
91 | |||
92 | if (bInterval < 6) | ||
93 | bInterval = 6; | ||
94 | if (bInterval > 10) | ||
95 | bInterval = 10; | ||
96 | return bInterval - 6; | ||
97 | } | ||
98 | |||
99 | static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset) | ||
100 | { | ||
101 | int period; | ||
102 | |||
103 | period = qset_get_period(whc, qset); | ||
104 | |||
105 | qset_clear(whc, qset); | ||
106 | list_move(&qset->list_node, &whc->periodic_list[period]); | ||
107 | qset->in_sw_list = true; | ||
108 | } | ||
109 | |||
110 | static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset) | ||
111 | { | ||
112 | list_move(&qset->list_node, &whc->periodic_removed_list); | ||
113 | qset->in_hw_list = false; | ||
114 | qset->in_sw_list = false; | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * pzl_process_qset - process any recently inactivated or halted qTDs | ||
119 | * in a qset. | ||
120 | * | ||
121 | * After inactive qTDs are removed, new qTDs can be added if the | ||
122 | * urb queue still contains URBs. | ||
123 | * | ||
124 | * Returns the schedule updates required. | ||
125 | */ | ||
126 | static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) | ||
127 | { | ||
128 | enum whc_update update = 0; | ||
129 | uint32_t status = 0; | ||
130 | |||
131 | while (qset->ntds) { | ||
132 | struct whc_qtd *td; | ||
133 | int t; | ||
134 | |||
135 | t = qset->td_start; | ||
136 | td = &qset->qtd[qset->td_start]; | ||
137 | status = le32_to_cpu(td->status); | ||
138 | |||
139 | /* | ||
140 | * Nothing to do with a still active qTD. | ||
141 | */ | ||
142 | if (status & QTD_STS_ACTIVE) | ||
143 | break; | ||
144 | |||
145 | if (status & QTD_STS_HALTED) { | ||
146 | /* Ug, an error. */ | ||
147 | process_halted_qtd(whc, qset, td); | ||
148 | goto done; | ||
149 | } | ||
150 | |||
151 | /* Mmm, a completed qTD. */ | ||
152 | process_inactive_qtd(whc, qset, td); | ||
153 | } | ||
154 | |||
155 | update |= qset_add_qtds(whc, qset); | ||
156 | |||
157 | done: | ||
158 | /* | ||
159 | * If there are no qTDs in this qset, remove it from the PZL. | ||
160 | */ | ||
161 | if (qset->remove && qset->ntds == 0) { | ||
162 | pzl_qset_remove(whc, qset); | ||
163 | update |= WHC_UPDATE_REMOVED; | ||
164 | } | ||
165 | |||
166 | return update; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * pzl_start - start the periodic schedule | ||
171 | * @whc: the WHCI host controller | ||
172 | * | ||
173 | * The PZL must be valid (e.g., all entries in the list should have | ||
174 | * the T bit set). | ||
175 | */ | ||
176 | void pzl_start(struct whc *whc) | ||
177 | { | ||
178 | le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); | ||
179 | |||
180 | whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN); | ||
181 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
182 | WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED, | ||
183 | 1000, "start PZL"); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * pzl_stop - stop the periodic schedule | ||
188 | * @whc: the WHCI host controller | ||
189 | */ | ||
190 | void pzl_stop(struct whc *whc) | ||
191 | { | ||
192 | whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0); | ||
193 | whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, | ||
194 | WUSBSTS_PERIODIC_SCHED, 0, | ||
195 | 1000, "stop PZL"); | ||
196 | } | ||
197 | |||
198 | void pzl_update(struct whc *whc, uint32_t wusbcmd) | ||
199 | { | ||
200 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
201 | wait_event(whc->periodic_list_wq, | ||
202 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); | ||
203 | } | ||
204 | |||
205 | static void update_pzl_hw_view(struct whc *whc) | ||
206 | { | ||
207 | struct whc_qset *qset, *t; | ||
208 | int period; | ||
209 | u64 tmp_qh = 0; | ||
210 | |||
211 | for (period = 0; period < 5; period++) { | ||
212 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { | ||
213 | whc_qset_set_link_ptr(&qset->qh.link, tmp_qh); | ||
214 | tmp_qh = qset->qset_dma; | ||
215 | qset->in_hw_list = true; | ||
216 | } | ||
217 | update_pzl_pointers(whc, period, tmp_qh); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * scan_periodic_work - scan the PZL for qsets to process. | ||
223 | * | ||
224 | * Process each qset in the PZL in turn and then signal the WHC that | ||
225 | * the PZL has been updated. | ||
226 | * | ||
227 | * Then start, stop or update the periodic schedule as required. | ||
228 | */ | ||
229 | void scan_periodic_work(struct work_struct *work) | ||
230 | { | ||
231 | struct whc *whc = container_of(work, struct whc, periodic_work); | ||
232 | struct whc_qset *qset, *t; | ||
233 | enum whc_update update = 0; | ||
234 | int period; | ||
235 | |||
236 | spin_lock_irq(&whc->lock); | ||
237 | |||
238 | dump_pzl(whc, "before processing"); | ||
239 | |||
240 | for (period = 4; period >= 0; period--) { | ||
241 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { | ||
242 | if (!qset->in_hw_list) | ||
243 | update |= WHC_UPDATE_ADDED; | ||
244 | update |= pzl_process_qset(whc, qset); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) | ||
249 | update_pzl_hw_view(whc); | ||
250 | |||
251 | dump_pzl(whc, "after processing"); | ||
252 | |||
253 | spin_unlock_irq(&whc->lock); | ||
254 | |||
255 | if (update) { | ||
256 | uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB; | ||
257 | if (update & WHC_UPDATE_REMOVED) | ||
258 | wusbcmd |= WUSBCMD_PERIODIC_QSET_RM; | ||
259 | pzl_update(whc, wusbcmd); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * Now that the PZL is updated, complete the removal of any | ||
264 | * removed qsets. | ||
265 | */ | ||
266 | spin_lock(&whc->lock); | ||
267 | |||
268 | list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { | ||
269 | qset_remove_complete(whc, qset); | ||
270 | } | ||
271 | |||
272 | spin_unlock(&whc->lock); | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * pzl_urb_enqueue - queue an URB onto the periodic list (PZL) | ||
277 | * @whc: the WHCI host controller | ||
278 | * @urb: the URB to enqueue | ||
279 | * @mem_flags: flags for any memory allocations | ||
280 | * | ||
281 | * The qset for the endpoint is obtained and the urb queued on to it. | ||
282 | * | ||
283 | * Work is scheduled to update the hardware's view of the PZL. | ||
284 | */ | ||
285 | int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | ||
286 | { | ||
287 | struct whc_qset *qset; | ||
288 | int err; | ||
289 | unsigned long flags; | ||
290 | |||
291 | spin_lock_irqsave(&whc->lock, flags); | ||
292 | |||
293 | qset = get_qset(whc, urb, GFP_ATOMIC); | ||
294 | if (qset == NULL) | ||
295 | err = -ENOMEM; | ||
296 | else | ||
297 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | ||
298 | if (!err) { | ||
299 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
300 | if (!qset->in_sw_list) | ||
301 | qset_insert_in_sw_list(whc, qset); | ||
302 | } | ||
303 | |||
304 | spin_unlock_irqrestore(&whc->lock, flags); | ||
305 | |||
306 | if (!err) | ||
307 | queue_work(whc->workqueue, &whc->periodic_work); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * pzl_urb_dequeue - remove an URB (qset) from the periodic list | ||
314 | * @whc: the WHCI host controller | ||
315 | * @urb: the URB to dequeue | ||
316 | * @status: the current status of the URB | ||
317 | * | ||
318 | * URBs that do yet have qTDs can simply be removed from the software | ||
319 | * queue, otherwise the qset must be removed so the qTDs can be safely | ||
320 | * removed. | ||
321 | */ | ||
322 | int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) | ||
323 | { | ||
324 | struct whc_urb *wurb = urb->hcpriv; | ||
325 | struct whc_qset *qset = wurb->qset; | ||
326 | struct whc_std *std, *t; | ||
327 | int ret; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave(&whc->lock, flags); | ||
331 | |||
332 | ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); | ||
333 | if (ret < 0) | ||
334 | goto out; | ||
335 | |||
336 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
337 | if (std->urb == urb) | ||
338 | qset_free_std(whc, std); | ||
339 | else | ||
340 | std->qtd = NULL; /* so this std is re-added when the qset is */ | ||
341 | } | ||
342 | |||
343 | pzl_qset_remove(whc, qset); | ||
344 | wurb->status = status; | ||
345 | wurb->is_async = false; | ||
346 | queue_work(whc->workqueue, &wurb->dequeue_work); | ||
347 | |||
348 | out: | ||
349 | spin_unlock_irqrestore(&whc->lock, flags); | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * pzl_qset_delete - delete a qset from the PZL | ||
356 | */ | ||
357 | void pzl_qset_delete(struct whc *whc, struct whc_qset *qset) | ||
358 | { | ||
359 | qset->remove = 1; | ||
360 | queue_work(whc->workqueue, &whc->periodic_work); | ||
361 | qset_delete(whc, qset); | ||
362 | } | ||
363 | |||
364 | |||
365 | /** | ||
366 | * pzl_init - initialize the periodic zone list | ||
367 | * @whc: the WHCI host controller | ||
368 | */ | ||
369 | int pzl_init(struct whc *whc) | ||
370 | { | ||
371 | int i; | ||
372 | |||
373 | whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16, | ||
374 | &whc->pz_list_dma, GFP_KERNEL); | ||
375 | if (whc->pz_list == NULL) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | /* Set T bit on all elements in PZL. */ | ||
379 | for (i = 0; i < 16; i++) | ||
380 | whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); | ||
381 | |||
382 | le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * pzl_clean_up - free PZL resources | ||
389 | * @whc: the WHCI host controller | ||
390 | * | ||
391 | * The PZL is stopped and empty. | ||
392 | */ | ||
393 | void pzl_clean_up(struct whc *whc) | ||
394 | { | ||
395 | if (whc->pz_list) | ||
396 | dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list, | ||
397 | whc->pz_list_dma); | ||
398 | } | ||
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c new file mode 100644 index 000000000000..0420037d2e18 --- /dev/null +++ b/drivers/usb/host/whci/qset.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) qset management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/uwb/umc.h> | ||
21 | #include <linux/usb.h> | ||
22 | |||
23 | #include "../../wusbcore/wusbhc.h" | ||
24 | |||
25 | #include "whcd.h" | ||
26 | |||
27 | void dump_qset(struct whc_qset *qset, struct device *dev) | ||
28 | { | ||
29 | struct whc_std *std; | ||
30 | struct urb *urb = NULL; | ||
31 | int i; | ||
32 | |||
33 | dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma); | ||
34 | dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link); | ||
35 | dev_dbg(dev, " info: %08x %08x %08x\n", | ||
36 | qset->qh.info1, qset->qh.info2, qset->qh.info3); | ||
37 | dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); | ||
38 | dev_dbg(dev, " TD: sts: %08x opts: %08x\n", | ||
39 | qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); | ||
40 | |||
41 | for (i = 0; i < WHCI_QSET_TD_MAX; i++) { | ||
42 | dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", | ||
43 | i == qset->td_start ? 'S' : ' ', | ||
44 | i == qset->td_end ? 'E' : ' ', | ||
45 | i, qset->qtd[i].status, qset->qtd[i].options, | ||
46 | (u32)qset->qtd[i].page_list_ptr); | ||
47 | } | ||
48 | dev_dbg(dev, " ntds: %d\n", qset->ntds); | ||
49 | list_for_each_entry(std, &qset->stds, list_node) { | ||
50 | if (urb != std->urb) { | ||
51 | urb = std->urb; | ||
52 | dev_dbg(dev, " urb %p transferred: %d bytes\n", urb, | ||
53 | urb->actual_length); | ||
54 | } | ||
55 | if (std->qtd) | ||
56 | dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n", | ||
57 | std->qtd - &qset->qtd[0], | ||
58 | std->len, std->num_pointers ? | ||
59 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
60 | else | ||
61 | dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n", | ||
62 | std->len, std->num_pointers ? | ||
63 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) | ||
68 | { | ||
69 | struct whc_qset *qset; | ||
70 | dma_addr_t dma; | ||
71 | |||
72 | qset = dma_pool_alloc(whc->qset_pool, mem_flags, &dma); | ||
73 | if (qset == NULL) | ||
74 | return NULL; | ||
75 | memset(qset, 0, sizeof(struct whc_qset)); | ||
76 | |||
77 | qset->qset_dma = dma; | ||
78 | qset->whc = whc; | ||
79 | |||
80 | INIT_LIST_HEAD(&qset->list_node); | ||
81 | INIT_LIST_HEAD(&qset->stds); | ||
82 | |||
83 | return qset; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * qset_fill_qh - fill the static endpoint state in a qset's QHead | ||
88 | * @qset: the qset whose QH needs initializing with static endpoint | ||
89 | * state | ||
90 | * @urb: an urb for a transfer to this endpoint | ||
91 | */ | ||
92 | static void qset_fill_qh(struct whc_qset *qset, struct urb *urb) | ||
93 | { | ||
94 | struct usb_device *usb_dev = urb->dev; | ||
95 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
96 | bool is_out; | ||
97 | |||
98 | is_out = usb_pipeout(urb->pipe); | ||
99 | |||
100 | epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra; | ||
101 | |||
102 | if (epcd) { | ||
103 | qset->max_seq = epcd->bMaxSequence; | ||
104 | qset->max_burst = epcd->bMaxBurst; | ||
105 | } else { | ||
106 | qset->max_seq = 2; | ||
107 | qset->max_burst = 1; | ||
108 | } | ||
109 | |||
110 | qset->qh.info1 = cpu_to_le32( | ||
111 | QH_INFO1_EP(usb_pipeendpoint(urb->pipe)) | ||
112 | | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN) | ||
113 | | usb_pipe_to_qh_type(urb->pipe) | ||
114 | | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum)) | ||
115 | | QH_INFO1_MAX_PKT_LEN(usb_maxpacket(urb->dev, urb->pipe, is_out)) | ||
116 | ); | ||
117 | qset->qh.info2 = cpu_to_le32( | ||
118 | QH_INFO2_BURST(qset->max_burst) | ||
119 | | QH_INFO2_DBP(0) | ||
120 | | QH_INFO2_MAX_COUNT(3) | ||
121 | | QH_INFO2_MAX_RETRY(3) | ||
122 | | QH_INFO2_MAX_SEQ(qset->max_seq - 1) | ||
123 | ); | ||
124 | /* FIXME: where can we obtain these Tx parameters from? Why | ||
125 | * doesn't the chip know what Tx power to use? It knows the Rx | ||
126 | * strength and can presumably guess the Tx power required | ||
127 | * from that? */ | ||
128 | qset->qh.info3 = cpu_to_le32( | ||
129 | QH_INFO3_TX_RATE_53_3 | ||
130 | | QH_INFO3_TX_PWR(0) /* 0 == max power */ | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * qset_clear - clear fields in a qset so it may be reinserted into a | ||
136 | * schedule | ||
137 | */ | ||
138 | void qset_clear(struct whc *whc, struct whc_qset *qset) | ||
139 | { | ||
140 | qset->td_start = qset->td_end = qset->ntds = 0; | ||
141 | qset->remove = 0; | ||
142 | |||
143 | qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); | ||
144 | qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start)); | ||
145 | qset->qh.err_count = 0; | ||
146 | qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); | ||
147 | qset->qh.scratch[0] = 0; | ||
148 | qset->qh.scratch[1] = 0; | ||
149 | qset->qh.scratch[2] = 0; | ||
150 | |||
151 | memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay)); | ||
152 | |||
153 | init_completion(&qset->remove_complete); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * get_qset - get the qset for an async endpoint | ||
158 | * | ||
159 | * A new qset is created if one does not already exist. | ||
160 | */ | ||
161 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, | ||
162 | gfp_t mem_flags) | ||
163 | { | ||
164 | struct whc_qset *qset; | ||
165 | |||
166 | qset = urb->ep->hcpriv; | ||
167 | if (qset == NULL) { | ||
168 | qset = qset_alloc(whc, mem_flags); | ||
169 | if (qset == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | qset->ep = urb->ep; | ||
173 | urb->ep->hcpriv = qset; | ||
174 | qset_fill_qh(qset, urb); | ||
175 | } | ||
176 | return qset; | ||
177 | } | ||
178 | |||
179 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset) | ||
180 | { | ||
181 | list_del_init(&qset->list_node); | ||
182 | complete(&qset->remove_complete); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * qset_add_qtds - add qTDs for an URB to a qset | ||
187 | * | ||
188 | * Returns true if the list (ASL/PZL) must be updated because (for a | ||
189 | * WHCI 0.95 controller) an activated qTD was pointed to be iCur. | ||
190 | */ | ||
191 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset) | ||
192 | { | ||
193 | struct whc_std *std; | ||
194 | enum whc_update update = 0; | ||
195 | |||
196 | list_for_each_entry(std, &qset->stds, list_node) { | ||
197 | struct whc_qtd *qtd; | ||
198 | uint32_t status; | ||
199 | |||
200 | if (qset->ntds >= WHCI_QSET_TD_MAX | ||
201 | || (qset->pause_after_urb && std->urb != qset->pause_after_urb)) | ||
202 | break; | ||
203 | |||
204 | if (std->qtd) | ||
205 | continue; /* already has a qTD */ | ||
206 | |||
207 | qtd = std->qtd = &qset->qtd[qset->td_end]; | ||
208 | |||
209 | /* Fill in setup bytes for control transfers. */ | ||
210 | if (usb_pipecontrol(std->urb->pipe)) | ||
211 | memcpy(qtd->setup, std->urb->setup_packet, 8); | ||
212 | |||
213 | status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len); | ||
214 | |||
215 | if (whc_std_last(std) && usb_pipeout(std->urb->pipe)) | ||
216 | status |= QTD_STS_LAST_PKT; | ||
217 | |||
218 | /* | ||
219 | * For an IN transfer the iAlt field should be set so | ||
220 | * the h/w will automatically advance to the next | ||
221 | * transfer. However, if there are 8 or more TDs | ||
222 | * remaining in this transfer then iAlt cannot be set | ||
223 | * as it could point to somewhere in this transfer. | ||
224 | */ | ||
225 | if (std->ntds_remaining < WHCI_QSET_TD_MAX) { | ||
226 | int ialt; | ||
227 | ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX; | ||
228 | status |= QTD_STS_IALT(ialt); | ||
229 | } else if (usb_pipein(std->urb->pipe)) | ||
230 | qset->pause_after_urb = std->urb; | ||
231 | |||
232 | if (std->num_pointers) | ||
233 | qtd->options = cpu_to_le32(QTD_OPT_IOC); | ||
234 | else | ||
235 | qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL); | ||
236 | qtd->page_list_ptr = cpu_to_le64(std->dma_addr); | ||
237 | |||
238 | qtd->status = cpu_to_le32(status); | ||
239 | |||
240 | if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end) | ||
241 | update = WHC_UPDATE_UPDATED; | ||
242 | |||
243 | if (++qset->td_end >= WHCI_QSET_TD_MAX) | ||
244 | qset->td_end = 0; | ||
245 | qset->ntds++; | ||
246 | } | ||
247 | |||
248 | return update; | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * qset_remove_qtd - remove the first qTD from a qset. | ||
253 | * | ||
254 | * The qTD might be still active (if it's part of a IN URB that | ||
255 | * resulted in a short read) so ensure it's deactivated. | ||
256 | */ | ||
257 | static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset) | ||
258 | { | ||
259 | qset->qtd[qset->td_start].status = 0; | ||
260 | |||
261 | if (++qset->td_start >= WHCI_QSET_TD_MAX) | ||
262 | qset->td_start = 0; | ||
263 | qset->ntds--; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * qset_free_std - remove an sTD and free it. | ||
268 | * @whc: the WHCI host controller | ||
269 | * @std: the sTD to remove and free. | ||
270 | */ | ||
271 | void qset_free_std(struct whc *whc, struct whc_std *std) | ||
272 | { | ||
273 | list_del(&std->list_node); | ||
274 | if (std->num_pointers) { | ||
275 | dma_unmap_single(whc->wusbhc.dev, std->dma_addr, | ||
276 | std->num_pointers * sizeof(struct whc_page_list_entry), | ||
277 | DMA_TO_DEVICE); | ||
278 | kfree(std->pl_virt); | ||
279 | } | ||
280 | |||
281 | kfree(std); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * qset_remove_qtds - remove an URB's qTDs (and sTDs). | ||
286 | */ | ||
287 | static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset, | ||
288 | struct urb *urb) | ||
289 | { | ||
290 | struct whc_std *std, *t; | ||
291 | |||
292 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
293 | if (std->urb != urb) | ||
294 | break; | ||
295 | if (std->qtd != NULL) | ||
296 | qset_remove_qtd(whc, qset); | ||
297 | qset_free_std(whc, std); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * qset_free_stds - free any remaining sTDs for an URB. | ||
303 | */ | ||
304 | static void qset_free_stds(struct whc_qset *qset, struct urb *urb) | ||
305 | { | ||
306 | struct whc_std *std, *t; | ||
307 | |||
308 | list_for_each_entry_safe(std, t, &qset->stds, list_node) { | ||
309 | if (std->urb == urb) | ||
310 | qset_free_std(qset->whc, std); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags) | ||
315 | { | ||
316 | dma_addr_t dma_addr = std->dma_addr; | ||
317 | dma_addr_t sp, ep; | ||
318 | size_t std_len = std->len; | ||
319 | size_t pl_len; | ||
320 | int p; | ||
321 | |||
322 | sp = ALIGN(dma_addr, WHCI_PAGE_SIZE); | ||
323 | ep = dma_addr + std_len; | ||
324 | std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE); | ||
325 | |||
326 | pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); | ||
327 | std->pl_virt = kmalloc(pl_len, mem_flags); | ||
328 | if (std->pl_virt == NULL) | ||
329 | return -ENOMEM; | ||
330 | std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); | ||
331 | |||
332 | for (p = 0; p < std->num_pointers; p++) { | ||
333 | std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); | ||
334 | dma_addr = ALIGN(dma_addr + WHCI_PAGE_SIZE, WHCI_PAGE_SIZE); | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system. | ||
342 | */ | ||
343 | static void urb_dequeue_work(struct work_struct *work) | ||
344 | { | ||
345 | struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work); | ||
346 | struct whc_qset *qset = wurb->qset; | ||
347 | struct whc *whc = qset->whc; | ||
348 | unsigned long flags; | ||
349 | |||
350 | if (wurb->is_async == true) | ||
351 | asl_update(whc, WUSBCMD_ASYNC_UPDATED | ||
352 | | WUSBCMD_ASYNC_SYNCED_DB | ||
353 | | WUSBCMD_ASYNC_QSET_RM); | ||
354 | else | ||
355 | pzl_update(whc, WUSBCMD_PERIODIC_UPDATED | ||
356 | | WUSBCMD_PERIODIC_SYNCED_DB | ||
357 | | WUSBCMD_PERIODIC_QSET_RM); | ||
358 | |||
359 | spin_lock_irqsave(&whc->lock, flags); | ||
360 | qset_remove_urb(whc, qset, wurb->urb, wurb->status); | ||
361 | spin_unlock_irqrestore(&whc->lock, flags); | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * qset_add_urb - add an urb to the qset's queue. | ||
366 | * | ||
367 | * The URB is chopped into sTDs, one for each qTD that will required. | ||
368 | * At least one qTD (and sTD) is required even if the transfer has no | ||
369 | * data (e.g., for some control transfers). | ||
370 | */ | ||
371 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, | ||
372 | gfp_t mem_flags) | ||
373 | { | ||
374 | struct whc_urb *wurb; | ||
375 | int remaining = urb->transfer_buffer_length; | ||
376 | u64 transfer_dma = urb->transfer_dma; | ||
377 | int ntds_remaining; | ||
378 | |||
379 | ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE); | ||
380 | if (ntds_remaining == 0) | ||
381 | ntds_remaining = 1; | ||
382 | |||
383 | wurb = kzalloc(sizeof(struct whc_urb), mem_flags); | ||
384 | if (wurb == NULL) | ||
385 | goto err_no_mem; | ||
386 | urb->hcpriv = wurb; | ||
387 | wurb->qset = qset; | ||
388 | wurb->urb = urb; | ||
389 | INIT_WORK(&wurb->dequeue_work, urb_dequeue_work); | ||
390 | |||
391 | while (ntds_remaining) { | ||
392 | struct whc_std *std; | ||
393 | size_t std_len; | ||
394 | |||
395 | std = kmalloc(sizeof(struct whc_std), mem_flags); | ||
396 | if (std == NULL) | ||
397 | goto err_no_mem; | ||
398 | |||
399 | std_len = remaining; | ||
400 | if (std_len > QTD_MAX_XFER_SIZE) | ||
401 | std_len = QTD_MAX_XFER_SIZE; | ||
402 | |||
403 | std->urb = urb; | ||
404 | std->dma_addr = transfer_dma; | ||
405 | std->len = std_len; | ||
406 | std->ntds_remaining = ntds_remaining; | ||
407 | std->qtd = NULL; | ||
408 | |||
409 | INIT_LIST_HEAD(&std->list_node); | ||
410 | list_add_tail(&std->list_node, &qset->stds); | ||
411 | |||
412 | if (std_len > WHCI_PAGE_SIZE) { | ||
413 | if (qset_fill_page_list(whc, std, mem_flags) < 0) | ||
414 | goto err_no_mem; | ||
415 | } else | ||
416 | std->num_pointers = 0; | ||
417 | |||
418 | ntds_remaining--; | ||
419 | remaining -= std_len; | ||
420 | transfer_dma += std_len; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | err_no_mem: | ||
426 | qset_free_stds(qset, urb); | ||
427 | return -ENOMEM; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * qset_remove_urb - remove an URB from the urb queue. | ||
432 | * | ||
433 | * The URB is returned to the USB subsystem. | ||
434 | */ | ||
435 | void qset_remove_urb(struct whc *whc, struct whc_qset *qset, | ||
436 | struct urb *urb, int status) | ||
437 | { | ||
438 | struct wusbhc *wusbhc = &whc->wusbhc; | ||
439 | struct whc_urb *wurb = urb->hcpriv; | ||
440 | |||
441 | usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb); | ||
442 | /* Drop the lock as urb->complete() may enqueue another urb. */ | ||
443 | spin_unlock(&whc->lock); | ||
444 | wusbhc_giveback_urb(wusbhc, urb, status); | ||
445 | spin_lock(&whc->lock); | ||
446 | |||
447 | kfree(wurb); | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * get_urb_status_from_qtd - get the completed urb status from qTD status | ||
452 | * @urb: completed urb | ||
453 | * @status: qTD status | ||
454 | */ | ||
455 | static int get_urb_status_from_qtd(struct urb *urb, u32 status) | ||
456 | { | ||
457 | if (status & QTD_STS_HALTED) { | ||
458 | if (status & QTD_STS_DBE) | ||
459 | return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM; | ||
460 | else if (status & QTD_STS_BABBLE) | ||
461 | return -EOVERFLOW; | ||
462 | else if (status & QTD_STS_RCE) | ||
463 | return -ETIME; | ||
464 | return -EPIPE; | ||
465 | } | ||
466 | if (usb_pipein(urb->pipe) | ||
467 | && (urb->transfer_flags & URB_SHORT_NOT_OK) | ||
468 | && urb->actual_length < urb->transfer_buffer_length) | ||
469 | return -EREMOTEIO; | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * process_inactive_qtd - process an inactive (but not halted) qTD. | ||
475 | * | ||
476 | * Update the urb with the transfer bytes from the qTD, if the urb is | ||
477 | * completely transfered or (in the case of an IN only) the LPF is | ||
478 | * set, then the transfer is complete and the urb should be returned | ||
479 | * to the system. | ||
480 | */ | ||
481 | void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, | ||
482 | struct whc_qtd *qtd) | ||
483 | { | ||
484 | struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); | ||
485 | struct urb *urb = std->urb; | ||
486 | uint32_t status; | ||
487 | bool complete; | ||
488 | |||
489 | status = le32_to_cpu(qtd->status); | ||
490 | |||
491 | urb->actual_length += std->len - QTD_STS_TO_LEN(status); | ||
492 | |||
493 | if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT)) | ||
494 | complete = true; | ||
495 | else | ||
496 | complete = whc_std_last(std); | ||
497 | |||
498 | qset_remove_qtd(whc, qset); | ||
499 | qset_free_std(whc, std); | ||
500 | |||
501 | /* | ||
502 | * Transfers for this URB are complete? Then return it to the | ||
503 | * USB subsystem. | ||
504 | */ | ||
505 | if (complete) { | ||
506 | qset_remove_qtds(whc, qset, urb); | ||
507 | qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status)); | ||
508 | |||
509 | /* | ||
510 | * If iAlt isn't valid then the hardware didn't | ||
511 | * advance iCur. Adjust the start and end pointers to | ||
512 | * match iCur. | ||
513 | */ | ||
514 | if (!(status & QTD_STS_IALT_VALID)) | ||
515 | qset->td_start = qset->td_end | ||
516 | = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status)); | ||
517 | qset->pause_after_urb = NULL; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * process_halted_qtd - process a qset with a halted qtd | ||
523 | * | ||
524 | * Remove all the qTDs for the failed URB and return the failed URB to | ||
525 | * the USB subsystem. Then remove all other qTDs so the qset can be | ||
526 | * removed. | ||
527 | * | ||
528 | * FIXME: this is the point where rate adaptation can be done. If a | ||
529 | * transfer failed because it exceeded the maximum number of retries | ||
530 | * then it could be reactivated with a slower rate without having to | ||
531 | * remove the qset. | ||
532 | */ | ||
533 | void process_halted_qtd(struct whc *whc, struct whc_qset *qset, | ||
534 | struct whc_qtd *qtd) | ||
535 | { | ||
536 | struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); | ||
537 | struct urb *urb = std->urb; | ||
538 | int urb_status; | ||
539 | |||
540 | urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status)); | ||
541 | |||
542 | qset_remove_qtds(whc, qset, urb); | ||
543 | qset_remove_urb(whc, qset, urb, urb_status); | ||
544 | |||
545 | list_for_each_entry(std, &qset->stds, list_node) { | ||
546 | if (qset->ntds == 0) | ||
547 | break; | ||
548 | qset_remove_qtd(whc, qset); | ||
549 | std->qtd = NULL; | ||
550 | } | ||
551 | |||
552 | qset->remove = 1; | ||
553 | } | ||
554 | |||
555 | void qset_free(struct whc *whc, struct whc_qset *qset) | ||
556 | { | ||
557 | dma_pool_free(whc->qset_pool, qset, qset->qset_dma); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * qset_delete - wait for a qset to be unused, then free it. | ||
562 | */ | ||
563 | void qset_delete(struct whc *whc, struct whc_qset *qset) | ||
564 | { | ||
565 | wait_for_completion(&qset->remove_complete); | ||
566 | qset_free(whc, qset); | ||
567 | } | ||
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h new file mode 100644 index 000000000000..1d2a53bd39fd --- /dev/null +++ b/drivers/usb/host/whci/whcd.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) private header. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA. | ||
19 | */ | ||
20 | #ifndef __WHCD_H | ||
21 | #define __WHCD_H | ||
22 | |||
23 | #include <linux/uwb/whci.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #include "whci-hc.h" | ||
27 | |||
28 | /* Generic command timeout. */ | ||
29 | #define WHC_GENCMD_TIMEOUT_MS 100 | ||
30 | |||
31 | |||
32 | struct whc { | ||
33 | struct wusbhc wusbhc; | ||
34 | struct umc_dev *umc; | ||
35 | |||
36 | resource_size_t base_phys; | ||
37 | void __iomem *base; | ||
38 | int irq; | ||
39 | |||
40 | u8 n_devices; | ||
41 | u8 n_keys; | ||
42 | u8 n_mmc_ies; | ||
43 | |||
44 | u64 *pz_list; | ||
45 | struct dn_buf_entry *dn_buf; | ||
46 | struct di_buf_entry *di_buf; | ||
47 | dma_addr_t pz_list_dma; | ||
48 | dma_addr_t dn_buf_dma; | ||
49 | dma_addr_t di_buf_dma; | ||
50 | |||
51 | spinlock_t lock; | ||
52 | struct mutex mutex; | ||
53 | |||
54 | void * gen_cmd_buf; | ||
55 | dma_addr_t gen_cmd_buf_dma; | ||
56 | wait_queue_head_t cmd_wq; | ||
57 | |||
58 | struct workqueue_struct *workqueue; | ||
59 | struct work_struct dn_work; | ||
60 | |||
61 | struct dma_pool *qset_pool; | ||
62 | |||
63 | struct list_head async_list; | ||
64 | struct list_head async_removed_list; | ||
65 | wait_queue_head_t async_list_wq; | ||
66 | struct work_struct async_work; | ||
67 | |||
68 | struct list_head periodic_list[5]; | ||
69 | struct list_head periodic_removed_list; | ||
70 | wait_queue_head_t periodic_list_wq; | ||
71 | struct work_struct periodic_work; | ||
72 | }; | ||
73 | |||
74 | #define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) | ||
75 | |||
76 | /** | ||
77 | * struct whc_std - a software TD. | ||
78 | * @urb: the URB this sTD is for. | ||
79 | * @offset: start of the URB's data for this TD. | ||
80 | * @len: the length of data in the associated TD. | ||
81 | * @ntds_remaining: number of TDs (starting from this one) in this transfer. | ||
82 | * | ||
83 | * Queued URBs may require more TDs than are available in a qset so we | ||
84 | * use a list of these "software TDs" (sTDs) to hold per-TD data. | ||
85 | */ | ||
86 | struct whc_std { | ||
87 | struct urb *urb; | ||
88 | size_t len; | ||
89 | int ntds_remaining; | ||
90 | struct whc_qtd *qtd; | ||
91 | |||
92 | struct list_head list_node; | ||
93 | int num_pointers; | ||
94 | dma_addr_t dma_addr; | ||
95 | struct whc_page_list_entry *pl_virt; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct whc_urb - per URB host controller structure. | ||
100 | * @urb: the URB this struct is for. | ||
101 | * @qset: the qset associated to the URB. | ||
102 | * @dequeue_work: the work to remove the URB when dequeued. | ||
103 | * @is_async: the URB belongs to async sheduler or not. | ||
104 | * @status: the status to be returned when calling wusbhc_giveback_urb. | ||
105 | */ | ||
106 | struct whc_urb { | ||
107 | struct urb *urb; | ||
108 | struct whc_qset *qset; | ||
109 | struct work_struct dequeue_work; | ||
110 | bool is_async; | ||
111 | int status; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * whc_std_last - is this sTD the URB's last? | ||
116 | * @std: the sTD to check. | ||
117 | */ | ||
118 | static inline bool whc_std_last(struct whc_std *std) | ||
119 | { | ||
120 | return std->ntds_remaining <= 1; | ||
121 | } | ||
122 | |||
123 | enum whc_update { | ||
124 | WHC_UPDATE_ADDED = 0x01, | ||
125 | WHC_UPDATE_REMOVED = 0x02, | ||
126 | WHC_UPDATE_UPDATED = 0x04, | ||
127 | }; | ||
128 | |||
129 | /* init.c */ | ||
130 | int whc_init(struct whc *whc); | ||
131 | void whc_clean_up(struct whc *whc); | ||
132 | |||
133 | /* hw.c */ | ||
134 | void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val); | ||
135 | int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); | ||
136 | |||
137 | /* wusb.c */ | ||
138 | int whc_wusbhc_start(struct wusbhc *wusbhc); | ||
139 | void whc_wusbhc_stop(struct wusbhc *wusbhc); | ||
140 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
141 | u8 handle, struct wuie_hdr *wuie); | ||
142 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); | ||
143 | int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm); | ||
144 | int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); | ||
145 | int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots); | ||
146 | int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
147 | const void *ptk, size_t key_size); | ||
148 | int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
149 | const void *gtk, size_t key_size); | ||
150 | int whc_set_cluster_id(struct whc *whc, u8 bcid); | ||
151 | |||
152 | /* int.c */ | ||
153 | irqreturn_t whc_int_handler(struct usb_hcd *hcd); | ||
154 | void whc_dn_work(struct work_struct *work); | ||
155 | |||
156 | /* asl.c */ | ||
157 | void asl_start(struct whc *whc); | ||
158 | void asl_stop(struct whc *whc); | ||
159 | int asl_init(struct whc *whc); | ||
160 | void asl_clean_up(struct whc *whc); | ||
161 | int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
162 | int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status); | ||
163 | void asl_qset_delete(struct whc *whc, struct whc_qset *qset); | ||
164 | void scan_async_work(struct work_struct *work); | ||
165 | |||
166 | /* pzl.c */ | ||
167 | int pzl_init(struct whc *whc); | ||
168 | void pzl_clean_up(struct whc *whc); | ||
169 | void pzl_start(struct whc *whc); | ||
170 | void pzl_stop(struct whc *whc); | ||
171 | int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
172 | int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status); | ||
173 | void pzl_qset_delete(struct whc *whc, struct whc_qset *qset); | ||
174 | void scan_periodic_work(struct work_struct *work); | ||
175 | |||
176 | /* qset.c */ | ||
177 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags); | ||
178 | void qset_free(struct whc *whc, struct whc_qset *qset); | ||
179 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); | ||
180 | void qset_delete(struct whc *whc, struct whc_qset *qset); | ||
181 | void qset_clear(struct whc *whc, struct whc_qset *qset); | ||
182 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, | ||
183 | gfp_t mem_flags); | ||
184 | void qset_free_std(struct whc *whc, struct whc_std *std); | ||
185 | void qset_remove_urb(struct whc *whc, struct whc_qset *qset, | ||
186 | struct urb *urb, int status); | ||
187 | void process_halted_qtd(struct whc *whc, struct whc_qset *qset, | ||
188 | struct whc_qtd *qtd); | ||
189 | void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, | ||
190 | struct whc_qtd *qtd); | ||
191 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); | ||
192 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset); | ||
193 | void dump_qset(struct whc_qset *qset, struct device *dev); | ||
194 | void pzl_update(struct whc *whc, uint32_t wusbcmd); | ||
195 | void asl_update(struct whc *whc, uint32_t wusbcmd); | ||
196 | |||
197 | #endif /* #ifndef __WHCD_H */ | ||
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h new file mode 100644 index 000000000000..bff1eb7a35cf --- /dev/null +++ b/drivers/usb/host/whci/whci-hc.h | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) data structures. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA. | ||
19 | */ | ||
20 | #ifndef _WHCI_WHCI_HC_H | ||
21 | #define _WHCI_WHCI_HC_H | ||
22 | |||
23 | #include <linux/list.h> | ||
24 | |||
25 | /** | ||
26 | * WHCI_PAGE_SIZE - page size use by WHCI | ||
27 | * | ||
28 | * WHCI assumes that host system uses pages of 4096 octets. | ||
29 | */ | ||
30 | #define WHCI_PAGE_SIZE 4096 | ||
31 | |||
32 | |||
33 | /** | ||
34 | * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single | ||
35 | * qtd. | ||
36 | * | ||
37 | * This is 2^20 - 1. | ||
38 | */ | ||
39 | #define QTD_MAX_XFER_SIZE 1048575 | ||
40 | |||
41 | |||
42 | /** | ||
43 | * struct whc_qtd - Queue Element Transfer Descriptors (qTD) | ||
44 | * | ||
45 | * This describes the data for a bulk, control or interrupt transfer. | ||
46 | * | ||
47 | * [WHCI] section 3.2.4 | ||
48 | */ | ||
49 | struct whc_qtd { | ||
50 | __le32 status; /*< remaining transfer len and transfer status */ | ||
51 | __le32 options; | ||
52 | __le64 page_list_ptr; /*< physical pointer to data buffer page list*/ | ||
53 | __u8 setup[8]; /*< setup data for control transfers */ | ||
54 | } __attribute__((packed)); | ||
55 | |||
56 | #define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */ | ||
57 | #define QTD_STS_HALTED (1 << 30) /* transfer halted */ | ||
58 | #define QTD_STS_DBE (1 << 29) /* data buffer error */ | ||
59 | #define QTD_STS_BABBLE (1 << 28) /* babble detected */ | ||
60 | #define QTD_STS_RCE (1 << 27) /* retry count exceeded */ | ||
61 | #define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */ | ||
62 | #define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */ | ||
63 | #define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */ | ||
64 | #define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */ | ||
65 | #define QTD_STS_LEN(l) ((l) << 0) /* transfer length */ | ||
66 | #define QTD_STS_TO_LEN(s) ((s) & 0x000fffff) | ||
67 | |||
68 | #define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */ | ||
69 | #define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */ | ||
70 | |||
71 | /** | ||
72 | * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD) | ||
73 | * | ||
74 | * This describes the data and other parameters for an isochronous | ||
75 | * transfer. | ||
76 | * | ||
77 | * [WHCI] section 3.2.5 | ||
78 | */ | ||
79 | struct whc_itd { | ||
80 | __le16 presentation_time; /*< presentation time for OUT transfers */ | ||
81 | __u8 num_segments; /*< number of data segments in segment list */ | ||
82 | __u8 status; /*< command execution status */ | ||
83 | __le32 options; /*< misc transfer options */ | ||
84 | __le64 page_list_ptr; /*< physical pointer to data buffer page list */ | ||
85 | __le64 seg_list_ptr; /*< physical pointer to segment list */ | ||
86 | } __attribute__((packed)); | ||
87 | |||
88 | #define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */ | ||
89 | #define ITD_STS_DBE (1 << 5) /* data buffer error */ | ||
90 | #define ITD_STS_BABBLE (1 << 4) /* babble detected */ | ||
91 | #define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */ | ||
92 | |||
93 | #define ITD_OPT_IOC (1 << 1) /* interrupt on complete */ | ||
94 | #define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */ | ||
95 | |||
96 | /** | ||
97 | * Page list entry. | ||
98 | * | ||
99 | * A TD's page list must contain sufficient page list entries for the | ||
100 | * total data length in the TD. | ||
101 | * | ||
102 | * [WHCI] section 3.2.4.3 | ||
103 | */ | ||
104 | struct whc_page_list_entry { | ||
105 | __le64 buf_ptr; /*< physical pointer to buffer */ | ||
106 | } __attribute__((packed)); | ||
107 | |||
108 | /** | ||
109 | * struct whc_seg_list_entry - Segment list entry. | ||
110 | * | ||
111 | * Describes a portion of the data buffer described in the containing | ||
112 | * qTD's page list. | ||
113 | * | ||
114 | * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr | ||
115 | * + qtd->seg_list_ptr[seg].offset; | ||
116 | * | ||
117 | * Segments can't cross page boundries. | ||
118 | * | ||
119 | * [WHCI] section 3.2.5.5 | ||
120 | */ | ||
121 | struct whc_seg_list_entry { | ||
122 | __le16 len; /*< segment length */ | ||
123 | __u8 idx; /*< index into page list */ | ||
124 | __u8 status; /*< segment status */ | ||
125 | __le16 offset; /*< 12 bit offset into page */ | ||
126 | } __attribute__((packed)); | ||
127 | |||
128 | /** | ||
129 | * struct whc_qhead - endpoint and status information for a qset. | ||
130 | * | ||
131 | * [WHCI] section 3.2.6 | ||
132 | */ | ||
133 | struct whc_qhead { | ||
134 | __le64 link; /*< next qset in list */ | ||
135 | __le32 info1; | ||
136 | __le32 info2; | ||
137 | __le32 info3; | ||
138 | __le16 status; | ||
139 | __le16 err_count; /*< transaction error count */ | ||
140 | __le32 cur_window; | ||
141 | __le32 scratch[3]; /*< h/w scratch area */ | ||
142 | union { | ||
143 | struct whc_qtd qtd; | ||
144 | struct whc_itd itd; | ||
145 | } overlay; | ||
146 | } __attribute__((packed)); | ||
147 | |||
148 | #define QH_LINK_PTR_MASK (~0x03Full) | ||
149 | #define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK) | ||
150 | #define QH_LINK_IQS (1 << 4) /* isochronous queue set */ | ||
151 | #define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */ | ||
152 | #define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */ | ||
153 | |||
154 | #define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */ | ||
155 | #define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */ | ||
156 | #define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */ | ||
157 | #define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */ | ||
158 | #define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */ | ||
159 | #define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */ | ||
160 | #define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */ | ||
161 | #define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */ | ||
162 | #define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */ | ||
163 | #define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */ | ||
164 | #define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */ | ||
165 | |||
166 | #define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */ | ||
167 | #define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */ | ||
168 | #define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */ | ||
169 | #define QH_INFO2_RQS (1 << 15) /* reactivate queue set */ | ||
170 | #define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */ | ||
171 | #define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */ | ||
172 | #define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */ | ||
173 | #define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */ | ||
174 | |||
175 | #define QH_INFO3_TX_RATE_53_3 (0 << 24) | ||
176 | #define QH_INFO3_TX_RATE_80 (1 << 24) | ||
177 | #define QH_INFO3_TX_RATE_106_7 (2 << 24) | ||
178 | #define QH_INFO3_TX_RATE_160 (3 << 24) | ||
179 | #define QH_INFO3_TX_RATE_200 (4 << 24) | ||
180 | #define QH_INFO3_TX_RATE_320 (5 << 24) | ||
181 | #define QH_INFO3_TX_RATE_400 (6 << 24) | ||
182 | #define QH_INFO3_TX_RATE_480 (7 << 24) | ||
183 | #define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */ | ||
184 | |||
185 | #define QH_STATUS_FLOW_CTRL (1 << 15) | ||
186 | #define QH_STATUS_ICUR(i) ((i) << 5) | ||
187 | #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) | ||
188 | |||
189 | /** | ||
190 | * usb_pipe_to_qh_type - USB core pipe type to QH transfer type | ||
191 | * | ||
192 | * Returns the QH type field for a USB core pipe type. | ||
193 | */ | ||
194 | static inline unsigned usb_pipe_to_qh_type(unsigned pipe) | ||
195 | { | ||
196 | static const unsigned type[] = { | ||
197 | [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC, | ||
198 | [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT, | ||
199 | [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL, | ||
200 | [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK, | ||
201 | }; | ||
202 | return type[usb_pipetype(pipe)]; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Maxiumum number of TDs in a qset. | ||
207 | */ | ||
208 | #define WHCI_QSET_TD_MAX 8 | ||
209 | |||
210 | /** | ||
211 | * struct whc_qset - WUSB data transfers to a specific endpoint | ||
212 | * @qh: the QHead of this qset | ||
213 | * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt | ||
214 | * transfers) | ||
215 | * @itd: up to 8 iTDs (for qsets for isochronous transfers) | ||
216 | * @qset_dma: DMA address for this qset | ||
217 | * @whc: WHCI HC this qset is for | ||
218 | * @ep: endpoint | ||
219 | * @stds: list of sTDs queued to this qset | ||
220 | * @ntds: number of qTDs queued (not necessarily the same as nTDs | ||
221 | * field in the QH) | ||
222 | * @td_start: index of the first qTD in the list | ||
223 | * @td_end: index of next free qTD in the list (provided | ||
224 | * ntds < WHCI_QSET_TD_MAX) | ||
225 | * | ||
226 | * Queue Sets (qsets) are added to the asynchronous schedule list | ||
227 | * (ASL) or the periodic zone list (PZL). | ||
228 | * | ||
229 | * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate). | ||
230 | * Each TD may refer to at most 1 MiB of data. If a single transfer | ||
231 | * has > 8MiB of data, TDs can be reused as they are completed since | ||
232 | * the TD list is used as a circular buffer. Similarly, several | ||
233 | * (smaller) transfers may be queued in a qset. | ||
234 | * | ||
235 | * WHCI controllers may cache portions of the qsets in the ASL and | ||
236 | * PZL, requiring the WHCD to inform the WHC that the lists have been | ||
237 | * updated (fields changed or qsets inserted or removed). For safe | ||
238 | * insertion and removal of qsets from the lists the schedule must be | ||
239 | * stopped to avoid races in updating the QH link pointers. | ||
240 | * | ||
241 | * Since the HC is free to execute qsets in any order, all transfers | ||
242 | * to an endpoint should use the same qset to ensure transfers are | ||
243 | * executed in the order they're submitted. | ||
244 | * | ||
245 | * [WHCI] section 3.2.3 | ||
246 | */ | ||
247 | struct whc_qset { | ||
248 | struct whc_qhead qh; | ||
249 | union { | ||
250 | struct whc_qtd qtd[WHCI_QSET_TD_MAX]; | ||
251 | struct whc_itd itd[WHCI_QSET_TD_MAX]; | ||
252 | }; | ||
253 | |||
254 | /* private data for WHCD */ | ||
255 | dma_addr_t qset_dma; | ||
256 | struct whc *whc; | ||
257 | struct usb_host_endpoint *ep; | ||
258 | struct list_head stds; | ||
259 | int ntds; | ||
260 | int td_start; | ||
261 | int td_end; | ||
262 | struct list_head list_node; | ||
263 | unsigned in_sw_list:1; | ||
264 | unsigned in_hw_list:1; | ||
265 | unsigned remove:1; | ||
266 | struct urb *pause_after_urb; | ||
267 | struct completion remove_complete; | ||
268 | int max_burst; | ||
269 | int max_seq; | ||
270 | }; | ||
271 | |||
272 | static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target) | ||
273 | { | ||
274 | if (target) | ||
275 | *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target); | ||
276 | else | ||
277 | *ptr = QH_LINK_T; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * struct di_buf_entry - Device Information (DI) buffer entry. | ||
282 | * | ||
283 | * There's one of these per connected device. | ||
284 | */ | ||
285 | struct di_buf_entry { | ||
286 | __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */ | ||
287 | __le32 addr_sec_info; /*< addressing and security info */ | ||
288 | __le32 reserved[7]; | ||
289 | } __attribute__((packed)); | ||
290 | |||
291 | #define WHC_DI_SECURE (1 << 31) | ||
292 | #define WHC_DI_DISABLE (1 << 30) | ||
293 | #define WHC_DI_KEY_IDX(k) ((k) << 8) | ||
294 | #define WHC_DI_KEY_IDX_MASK 0x0000ff00 | ||
295 | #define WHC_DI_DEV_ADDR(a) ((a) << 0) | ||
296 | #define WHC_DI_DEV_ADDR_MASK 0x000000ff | ||
297 | |||
298 | /** | ||
299 | * struct dn_buf_entry - Device Notification (DN) buffer entry. | ||
300 | * | ||
301 | * [WHCI] section 3.2.8 | ||
302 | */ | ||
303 | struct dn_buf_entry { | ||
304 | __u8 msg_size; /*< number of octets of valid DN data */ | ||
305 | __u8 reserved1; | ||
306 | __u8 src_addr; /*< source address */ | ||
307 | __u8 status; /*< buffer entry status */ | ||
308 | __le32 tkid; /*< TKID for source device, valid if secure bit is set */ | ||
309 | __u8 dn_data[56]; /*< up to 56 octets of DN data */ | ||
310 | } __attribute__((packed)); | ||
311 | |||
312 | #define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */ | ||
313 | #define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */ | ||
314 | |||
315 | #define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry)) | ||
316 | |||
317 | /* The Add MMC IE WUSB Generic Command may take up to 256 bytes of | ||
318 | data. [WHCI] section 2.4.7. */ | ||
319 | #define WHC_GEN_CMD_DATA_LEN 256 | ||
320 | |||
321 | /* | ||
322 | * HC registers. | ||
323 | * | ||
324 | * [WHCI] section 2.4 | ||
325 | */ | ||
326 | |||
327 | #define WHCIVERSION 0x00 | ||
328 | |||
329 | #define WHCSPARAMS 0x04 | ||
330 | # define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff) | ||
331 | # define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff) | ||
332 | # define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f) | ||
333 | |||
334 | #define WUSBCMD 0x08 | ||
335 | # define WUSBCMD_BCID(b) ((b) << 16) | ||
336 | # define WUSBCMD_BCID_MASK (0xff << 16) | ||
337 | # define WUSBCMD_ASYNC_QSET_RM (1 << 12) | ||
338 | # define WUSBCMD_PERIODIC_QSET_RM (1 << 11) | ||
339 | # define WUSBCMD_WUSBSI(s) ((s) << 8) | ||
340 | # define WUSBCMD_WUSBSI_MASK (0x7 << 8) | ||
341 | # define WUSBCMD_ASYNC_SYNCED_DB (1 << 7) | ||
342 | # define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6) | ||
343 | # define WUSBCMD_ASYNC_UPDATED (1 << 5) | ||
344 | # define WUSBCMD_PERIODIC_UPDATED (1 << 4) | ||
345 | # define WUSBCMD_ASYNC_EN (1 << 3) | ||
346 | # define WUSBCMD_PERIODIC_EN (1 << 2) | ||
347 | # define WUSBCMD_WHCRESET (1 << 1) | ||
348 | # define WUSBCMD_RUN (1 << 0) | ||
349 | |||
350 | #define WUSBSTS 0x0c | ||
351 | # define WUSBSTS_ASYNC_SCHED (1 << 15) | ||
352 | # define WUSBSTS_PERIODIC_SCHED (1 << 14) | ||
353 | # define WUSBSTS_DNTS_SCHED (1 << 13) | ||
354 | # define WUSBSTS_HCHALTED (1 << 12) | ||
355 | # define WUSBSTS_GEN_CMD_DONE (1 << 9) | ||
356 | # define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8) | ||
357 | # define WUSBSTS_DNTS_OVERFLOW (1 << 7) | ||
358 | # define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6) | ||
359 | # define WUSBSTS_HOST_ERR (1 << 5) | ||
360 | # define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4) | ||
361 | # define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3) | ||
362 | # define WUSBSTS_DNTS_INT (1 << 2) | ||
363 | # define WUSBSTS_ERR_INT (1 << 1) | ||
364 | # define WUSBSTS_INT (1 << 0) | ||
365 | # define WUSBSTS_INT_MASK 0x3ff | ||
366 | |||
367 | #define WUSBINTR 0x10 | ||
368 | # define WUSBINTR_GEN_CMD_DONE (1 << 9) | ||
369 | # define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8) | ||
370 | # define WUSBINTR_DNTS_OVERFLOW (1 << 7) | ||
371 | # define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6) | ||
372 | # define WUSBINTR_HOST_ERR (1 << 5) | ||
373 | # define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4) | ||
374 | # define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3) | ||
375 | # define WUSBINTR_DNTS_INT (1 << 2) | ||
376 | # define WUSBINTR_ERR_INT (1 << 1) | ||
377 | # define WUSBINTR_INT (1 << 0) | ||
378 | # define WUSBINTR_ALL 0x3ff | ||
379 | |||
380 | #define WUSBGENCMDSTS 0x14 | ||
381 | # define WUSBGENCMDSTS_ACTIVE (1 << 31) | ||
382 | # define WUSBGENCMDSTS_ERROR (1 << 24) | ||
383 | # define WUSBGENCMDSTS_IOC (1 << 23) | ||
384 | # define WUSBGENCMDSTS_MMCIE_ADD 0x01 | ||
385 | # define WUSBGENCMDSTS_MMCIE_RM 0x02 | ||
386 | # define WUSBGENCMDSTS_SET_MAS 0x03 | ||
387 | # define WUSBGENCMDSTS_CHAN_STOP 0x04 | ||
388 | # define WUSBGENCMDSTS_RWP_EN 0x05 | ||
389 | |||
390 | #define WUSBGENCMDPARAMS 0x18 | ||
391 | #define WUSBGENADDR 0x20 | ||
392 | #define WUSBASYNCLISTADDR 0x28 | ||
393 | #define WUSBDNTSBUFADDR 0x30 | ||
394 | #define WUSBDEVICEINFOADDR 0x38 | ||
395 | |||
396 | #define WUSBSETSECKEYCMD 0x40 | ||
397 | # define WUSBSETSECKEYCMD_SET (1 << 31) | ||
398 | # define WUSBSETSECKEYCMD_ERASE (1 << 30) | ||
399 | # define WUSBSETSECKEYCMD_GTK (1 << 8) | ||
400 | # define WUSBSETSECKEYCMD_IDX(i) ((i) << 0) | ||
401 | |||
402 | #define WUSBTKID 0x44 | ||
403 | #define WUSBSECKEY 0x48 | ||
404 | #define WUSBPERIODICLISTBASE 0x58 | ||
405 | #define WUSBMASINDEX 0x60 | ||
406 | |||
407 | #define WUSBDNTSCTRL 0x64 | ||
408 | # define WUSBDNTSCTRL_ACTIVE (1 << 31) | ||
409 | # define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8) | ||
410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) | ||
411 | |||
412 | #define WUSBTIME 0x68 | ||
413 | #define WUSBBPST 0x6c | ||
414 | #define WUSBDIBUPDATED 0x70 | ||
415 | |||
416 | #endif /* #ifndef _WHCI_WHCI_HC_H */ | ||
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c new file mode 100644 index 000000000000..66e4ddcd961d --- /dev/null +++ b/drivers/usb/host/whci/wusb.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) WUSB operations. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/uwb/umc.h> | ||
22 | #define D_LOCAL 1 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | |||
25 | #include "../../wusbcore/wusbhc.h" | ||
26 | |||
27 | #include "whcd.h" | ||
28 | |||
29 | #if D_LOCAL >= 1 | ||
30 | static void dump_di(struct whc *whc, int idx) | ||
31 | { | ||
32 | struct di_buf_entry *di = &whc->di_buf[idx]; | ||
33 | struct device *dev = &whc->umc->dev; | ||
34 | char buf[128]; | ||
35 | |||
36 | bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS); | ||
37 | |||
38 | d_printf(1, dev, "DI[%d]\n", idx); | ||
39 | d_printf(1, dev, " availability: %s\n", buf); | ||
40 | d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n", | ||
41 | (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', | ||
42 | (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', | ||
43 | (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, | ||
44 | (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); | ||
45 | } | ||
46 | #else | ||
47 | static inline void dump_di(struct whc *whc, int idx) | ||
48 | { | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | static int whc_update_di(struct whc *whc, int idx) | ||
53 | { | ||
54 | int offset = idx / 32; | ||
55 | u32 bit = 1 << (idx % 32); | ||
56 | |||
57 | dump_di(whc, idx); | ||
58 | |||
59 | le_writel(bit, whc->base + WUSBDIBUPDATED + offset); | ||
60 | |||
61 | return whci_wait_for(&whc->umc->dev, | ||
62 | whc->base + WUSBDIBUPDATED + offset, bit, 0, | ||
63 | 100, "DI update"); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * WHCI starts and stops MMCs based on there being a valid GTK so | ||
68 | * these need only start/stop the asynchronous and periodic schedules. | ||
69 | */ | ||
70 | |||
71 | int whc_wusbhc_start(struct wusbhc *wusbhc) | ||
72 | { | ||
73 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
74 | |||
75 | asl_start(whc); | ||
76 | pzl_start(whc); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | void whc_wusbhc_stop(struct wusbhc *wusbhc) | ||
82 | { | ||
83 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
84 | |||
85 | pzl_stop(whc); | ||
86 | asl_stop(whc); | ||
87 | } | ||
88 | |||
89 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
90 | u8 handle, struct wuie_hdr *wuie) | ||
91 | { | ||
92 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
93 | u32 params; | ||
94 | |||
95 | params = (interval << 24) | ||
96 | | (repeat_cnt << 16) | ||
97 | | (wuie->bLength << 8) | ||
98 | | handle; | ||
99 | |||
100 | return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength); | ||
101 | } | ||
102 | |||
103 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle) | ||
104 | { | ||
105 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
106 | u32 params; | ||
107 | |||
108 | params = handle; | ||
109 | |||
110 | return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0); | ||
111 | } | ||
112 | |||
113 | int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm) | ||
114 | { | ||
115 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
116 | |||
117 | if (stream_index >= 0) | ||
118 | whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index)); | ||
119 | |||
120 | return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm)); | ||
121 | } | ||
122 | |||
123 | int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
124 | { | ||
125 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
126 | int idx = wusb_dev->port_idx; | ||
127 | struct di_buf_entry *di = &whc->di_buf[idx]; | ||
128 | int ret; | ||
129 | |||
130 | mutex_lock(&whc->mutex); | ||
131 | |||
132 | uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability); | ||
133 | di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK); | ||
134 | di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr); | ||
135 | |||
136 | ret = whc_update_di(whc, idx); | ||
137 | |||
138 | mutex_unlock(&whc->mutex); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Set the number of Device Notification Time Slots (DNTS) and enable | ||
145 | * device notifications. | ||
146 | */ | ||
147 | int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) | ||
148 | { | ||
149 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
150 | u32 dntsctrl; | ||
151 | |||
152 | dntsctrl = WUSBDNTSCTRL_ACTIVE | ||
153 | | WUSBDNTSCTRL_INTERVAL(interval) | ||
154 | | WUSBDNTSCTRL_SLOTS(slots); | ||
155 | |||
156 | le_writel(dntsctrl, whc->base + WUSBDNTSCTRL); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid, | ||
162 | const void *key, size_t key_size, bool is_gtk) | ||
163 | { | ||
164 | uint32_t setkeycmd; | ||
165 | uint32_t seckey[4]; | ||
166 | int i; | ||
167 | int ret; | ||
168 | |||
169 | memcpy(seckey, key, key_size); | ||
170 | setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index); | ||
171 | if (is_gtk) | ||
172 | setkeycmd |= WUSBSETSECKEYCMD_GTK; | ||
173 | |||
174 | le_writel(tkid, whc->base + WUSBTKID); | ||
175 | for (i = 0; i < 4; i++) | ||
176 | le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i); | ||
177 | le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD); | ||
178 | |||
179 | ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD, | ||
180 | WUSBSETSECKEYCMD_SET, 0, 100, "set key"); | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * whc_set_ptk - set the PTK to use for a device. | ||
187 | * | ||
188 | * The index into the key table for this PTK is the same as the | ||
189 | * device's port index. | ||
190 | */ | ||
191 | int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, | ||
192 | const void *ptk, size_t key_size) | ||
193 | { | ||
194 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
195 | struct di_buf_entry *di = &whc->di_buf[port_idx]; | ||
196 | int ret; | ||
197 | |||
198 | mutex_lock(&whc->mutex); | ||
199 | |||
200 | if (ptk) { | ||
201 | ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false); | ||
202 | if (ret) | ||
203 | goto out; | ||
204 | |||
205 | di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK; | ||
206 | di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx); | ||
207 | } else | ||
208 | di->addr_sec_info &= ~WHC_DI_SECURE; | ||
209 | |||
210 | ret = whc_update_di(whc, port_idx); | ||
211 | out: | ||
212 | mutex_unlock(&whc->mutex); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * whc_set_gtk - set the GTK for subsequent broadcast packets | ||
218 | * | ||
219 | * The GTK is stored in the last entry in the key table (the previous | ||
220 | * N_DEVICES entries are for the per-device PTKs). | ||
221 | */ | ||
222 | int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, | ||
223 | const void *gtk, size_t key_size) | ||
224 | { | ||
225 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
226 | int ret; | ||
227 | |||
228 | mutex_lock(&whc->mutex); | ||
229 | |||
230 | ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true); | ||
231 | |||
232 | mutex_unlock(&whc->mutex); | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | int whc_set_cluster_id(struct whc *whc, u8 bcid) | ||
238 | { | ||
239 | whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid)); | ||
240 | return 0; | ||
241 | } | ||
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig new file mode 100644 index 000000000000..eb09a0a14a80 --- /dev/null +++ b/drivers/usb/wusbcore/Kconfig | |||
@@ -0,0 +1,41 @@ | |||
1 | # | ||
2 | # Wireless USB Core configuration | ||
3 | # | ||
4 | config USB_WUSB | ||
5 | tristate "Enable Wireless USB extensions (EXPERIMENTAL)" | ||
6 | depends on EXPERIMENTAL | ||
7 | depends on USB | ||
8 | select UWB | ||
9 | select CRYPTO | ||
10 | select CRYPTO_BLKCIPHER | ||
11 | select CRYPTO_CBC | ||
12 | select CRYPTO_MANAGER | ||
13 | select CRYPTO_AES | ||
14 | help | ||
15 | Enable the host-side support for Wireless USB. | ||
16 | |||
17 | To compile this support select Y (built in). It is safe to | ||
18 | select even if you don't have the hardware. | ||
19 | |||
20 | config USB_WUSB_CBAF | ||
21 | tristate "Support WUSB Cable Based Association (CBA)" | ||
22 | depends on USB | ||
23 | help | ||
24 | Some WUSB devices support Cable Based Association. It's used to | ||
25 | enable the secure communication between the host and the | ||
26 | device. | ||
27 | |||
28 | Enable this option if your WUSB device must to be connected | ||
29 | via wired USB before establishing a wireless link. | ||
30 | |||
31 | It is safe to select even if you don't have a compatible | ||
32 | hardware. | ||
33 | |||
34 | config USB_WUSB_CBAF_DEBUG | ||
35 | bool "Enable CBA debug messages" | ||
36 | depends on USB_WUSB_CBAF | ||
37 | help | ||
38 | Say Y here if you want the CBA to produce a bunch of debug messages | ||
39 | to the system log. Select this if you are having a problem with | ||
40 | CBA support and want to see more of what is going on. | ||
41 | |||
diff --git a/drivers/usb/wusbcore/Makefile b/drivers/usb/wusbcore/Makefile new file mode 100644 index 000000000000..75f1ade66258 --- /dev/null +++ b/drivers/usb/wusbcore/Makefile | |||
@@ -0,0 +1,26 @@ | |||
1 | obj-$(CONFIG_USB_WUSB) += wusbcore.o | ||
2 | obj-$(CONFIG_USB_HWA_HCD) += wusb-wa.o | ||
3 | obj-$(CONFIG_USB_WUSB_CBAF) += wusb-cbaf.o | ||
4 | |||
5 | |||
6 | wusbcore-objs := \ | ||
7 | crypto.o \ | ||
8 | devconnect.o \ | ||
9 | dev-sysfs.o \ | ||
10 | mmc.o \ | ||
11 | pal.o \ | ||
12 | rh.o \ | ||
13 | reservation.o \ | ||
14 | security.o \ | ||
15 | wusbhc.o | ||
16 | |||
17 | wusb-cbaf-objs := cbaf.o | ||
18 | |||
19 | wusb-wa-objs := wa-hc.o \ | ||
20 | wa-nep.o \ | ||
21 | wa-rpipe.o \ | ||
22 | wa-xfer.o | ||
23 | |||
24 | ifeq ($(CONFIG_USB_WUSB_CBAF_DEBUG),y) | ||
25 | EXTRA_CFLAGS += -DDEBUG | ||
26 | endif | ||
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c new file mode 100644 index 000000000000..ab4788d1785a --- /dev/null +++ b/drivers/usb/wusbcore/cbaf.c | |||
@@ -0,0 +1,673 @@ | |||
1 | /* | ||
2 | * Wireless USB - Cable Based Association | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * WUSB devices have to be paired (associated in WUSB lingo) so | ||
25 | * that they can connect to the system. | ||
26 | * | ||
27 | * One way of pairing is using CBA-Cable Based Association. First | ||
28 | * time you plug the device with a cable, association is done between | ||
29 | * host and device and subsequent times, you can connect wirelessly | ||
30 | * without having to associate again. That's the idea. | ||
31 | * | ||
32 | * This driver does nothing Earth shattering. It just provides an | ||
33 | * interface to chat with the wire-connected device so we can get a | ||
34 | * CDID (device ID) that might have been previously associated to a | ||
35 | * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet | ||
36 | * (connection context), with the CK being the secret, or connection | ||
37 | * key. This is the pairing data. | ||
38 | * | ||
39 | * When a device with the CBA capability connects, the probe routine | ||
40 | * just creates a bunch of sysfs files that a user space enumeration | ||
41 | * manager uses to allow it to connect wirelessly to the system or not. | ||
42 | * | ||
43 | * The process goes like this: | ||
44 | * | ||
45 | * 1. Device plugs, cbaf is loaded, notifications happen. | ||
46 | * | ||
47 | * 2. The connection manager (CM) sees a device with CBAF capability | ||
48 | * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE). | ||
49 | * | ||
50 | * 3. The CM writes the host name, supported band groups, and the CHID | ||
51 | * (host ID) into the wusb_host_name, wusb_host_band_groups and | ||
52 | * wusb_chid files. These get sent to the device and the CDID (if | ||
53 | * any) for this host is requested. | ||
54 | * | ||
55 | * 4. The CM can verify that the device's supported band groups | ||
56 | * (wusb_device_band_groups) are compatible with the host. | ||
57 | * | ||
58 | * 5. The CM reads the wusb_cdid file. | ||
59 | * | ||
60 | * 6. The CM looks up its database | ||
61 | * | ||
62 | * 6.1 If it has a matching CHID,CDID entry, the device has been | ||
63 | * authorized before (paired) and nothing further needs to be | ||
64 | * done. | ||
65 | * | ||
66 | * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in | ||
67 | * its database), the device is assumed to be not known. The CM | ||
68 | * may associate the host with device by: writing a randomly | ||
69 | * generated CDID to wusb_cdid and then a random CK to wusb_ck | ||
70 | * (this uploads the new CC to the device). | ||
71 | * | ||
72 | * CMD may choose to prompt the user before associating with a new | ||
73 | * device. | ||
74 | * | ||
75 | * 7. Device is unplugged. | ||
76 | * | ||
77 | * When the device tries to connect wirelessly, it will present its | ||
78 | * CDID to the WUSB host controller. The CM will query the | ||
79 | * database. If the CHID/CDID pair found, it will (with a 4-way | ||
80 | * handshake) challenge the device to demonstrate it has the CK secret | ||
81 | * key (from our database) without actually exchanging it. Once | ||
82 | * satisfied, crypto keys are derived from the CK, the device is | ||
83 | * connected and all communication is encrypted. | ||
84 | * | ||
85 | * References: | ||
86 | * [WUSB-AM] Association Models Supplement to the Certified Wireless | ||
87 | * Universal Serial Bus Specification, version 1.0. | ||
88 | */ | ||
89 | #include <linux/module.h> | ||
90 | #include <linux/ctype.h> | ||
91 | #include <linux/version.h> | ||
92 | #include <linux/usb.h> | ||
93 | #include <linux/interrupt.h> | ||
94 | #include <linux/delay.h> | ||
95 | #include <linux/random.h> | ||
96 | #include <linux/mutex.h> | ||
97 | #include <linux/uwb.h> | ||
98 | #include <linux/usb/wusb.h> | ||
99 | #include <linux/usb/association.h> | ||
100 | |||
101 | #define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */ | ||
102 | |||
103 | /* An instance of a Cable-Based-Association-Framework device */ | ||
104 | struct cbaf { | ||
105 | struct usb_device *usb_dev; | ||
106 | struct usb_interface *usb_iface; | ||
107 | void *buffer; | ||
108 | size_t buffer_size; | ||
109 | |||
110 | struct wusb_ckhdid chid; | ||
111 | char host_name[CBA_NAME_LEN]; | ||
112 | u16 host_band_groups; | ||
113 | |||
114 | struct wusb_ckhdid cdid; | ||
115 | char device_name[CBA_NAME_LEN]; | ||
116 | u16 device_band_groups; | ||
117 | |||
118 | struct wusb_ckhdid ck; | ||
119 | }; | ||
120 | |||
121 | /* | ||
122 | * Verify that a CBAF USB-interface has what we need | ||
123 | * | ||
124 | * According to [WUSB-AM], CBA devices should provide at least two | ||
125 | * interfaces: | ||
126 | * - RETRIEVE_HOST_INFO | ||
127 | * - ASSOCIATE | ||
128 | * | ||
129 | * If the device doesn't provide these interfaces, we do not know how | ||
130 | * to deal with it. | ||
131 | */ | ||
132 | static int cbaf_check(struct cbaf *cbaf) | ||
133 | { | ||
134 | int result; | ||
135 | struct device *dev = &cbaf->usb_iface->dev; | ||
136 | struct wusb_cbaf_assoc_info *assoc_info; | ||
137 | struct wusb_cbaf_assoc_request *assoc_request; | ||
138 | size_t assoc_size; | ||
139 | void *itr, *top; | ||
140 | int ar_rhi = 0, ar_assoc = 0; | ||
141 | |||
142 | result = usb_control_msg( | ||
143 | cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), | ||
144 | CBAF_REQ_GET_ASSOCIATION_INFORMATION, | ||
145 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
146 | 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
147 | cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); | ||
148 | if (result < 0) { | ||
149 | dev_err(dev, "Cannot get available association types: %d\n", | ||
150 | result); | ||
151 | return result; | ||
152 | } | ||
153 | |||
154 | assoc_info = cbaf->buffer; | ||
155 | if (result < sizeof(*assoc_info)) { | ||
156 | dev_err(dev, "Not enough data to decode association info " | ||
157 | "header (%zu vs %zu bytes required)\n", | ||
158 | (size_t)result, sizeof(*assoc_info)); | ||
159 | return result; | ||
160 | } | ||
161 | |||
162 | assoc_size = le16_to_cpu(assoc_info->Length); | ||
163 | if (result < assoc_size) { | ||
164 | dev_err(dev, "Not enough data to decode association info " | ||
165 | "(%zu vs %zu bytes required)\n", | ||
166 | (size_t)assoc_size, sizeof(*assoc_info)); | ||
167 | return result; | ||
168 | } | ||
169 | /* | ||
170 | * From now on, we just verify, but won't error out unless we | ||
171 | * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE} | ||
172 | * types. | ||
173 | */ | ||
174 | itr = cbaf->buffer + sizeof(*assoc_info); | ||
175 | top = cbaf->buffer + assoc_size; | ||
176 | dev_dbg(dev, "Found %u association requests (%zu bytes)\n", | ||
177 | assoc_info->NumAssociationRequests, assoc_size); | ||
178 | |||
179 | while (itr < top) { | ||
180 | u16 ar_type, ar_subtype; | ||
181 | u32 ar_size; | ||
182 | const char *ar_name; | ||
183 | |||
184 | assoc_request = itr; | ||
185 | |||
186 | if (top - itr < sizeof(*assoc_request)) { | ||
187 | dev_err(dev, "Not enough data to decode associaton " | ||
188 | "request (%zu vs %zu bytes needed)\n", | ||
189 | top - itr, sizeof(*assoc_request)); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | ar_type = le16_to_cpu(assoc_request->AssociationTypeId); | ||
194 | ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId); | ||
195 | ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize); | ||
196 | ar_name = "unknown"; | ||
197 | |||
198 | switch (ar_type) { | ||
199 | case AR_TYPE_WUSB: | ||
200 | /* Verify we have what is mandated by [WUSB-AM]. */ | ||
201 | switch (ar_subtype) { | ||
202 | case AR_TYPE_WUSB_RETRIEVE_HOST_INFO: | ||
203 | ar_name = "RETRIEVE_HOST_INFO"; | ||
204 | ar_rhi = 1; | ||
205 | break; | ||
206 | case AR_TYPE_WUSB_ASSOCIATE: | ||
207 | /* send assoc data */ | ||
208 | ar_name = "ASSOCIATE"; | ||
209 | ar_assoc = 1; | ||
210 | break; | ||
211 | }; | ||
212 | break; | ||
213 | }; | ||
214 | |||
215 | dev_dbg(dev, "Association request #%02u: 0x%04x/%04x " | ||
216 | "(%zu bytes): %s\n", | ||
217 | assoc_request->AssociationDataIndex, ar_type, | ||
218 | ar_subtype, (size_t)ar_size, ar_name); | ||
219 | |||
220 | itr += sizeof(*assoc_request); | ||
221 | } | ||
222 | |||
223 | if (!ar_rhi) { | ||
224 | dev_err(dev, "Missing RETRIEVE_HOST_INFO association " | ||
225 | "request\n"); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | if (!ar_assoc) { | ||
229 | dev_err(dev, "Missing ASSOCIATE association request\n"); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static const struct wusb_cbaf_host_info cbaf_host_info_defaults = { | ||
237 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
238 | .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), | ||
239 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
240 | .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO), | ||
241 | .CHID_hdr = WUSB_AR_CHID, | ||
242 | .LangID_hdr = WUSB_AR_LangID, | ||
243 | .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName, | ||
244 | }; | ||
245 | |||
246 | /* Send WUSB host information (CHID and name) to a CBAF device */ | ||
247 | static int cbaf_send_host_info(struct cbaf *cbaf) | ||
248 | { | ||
249 | struct wusb_cbaf_host_info *hi; | ||
250 | size_t name_len; | ||
251 | size_t hi_size; | ||
252 | |||
253 | hi = cbaf->buffer; | ||
254 | memset(hi, 0, sizeof(*hi)); | ||
255 | *hi = cbaf_host_info_defaults; | ||
256 | hi->CHID = cbaf->chid; | ||
257 | hi->LangID = 0; /* FIXME: I guess... */ | ||
258 | strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN); | ||
259 | name_len = strlen(cbaf->host_name); | ||
260 | hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len); | ||
261 | hi_size = sizeof(*hi) + name_len; | ||
262 | |||
263 | return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), | ||
264 | CBAF_REQ_SET_ASSOCIATION_RESPONSE, | ||
265 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
266 | 0x0101, | ||
267 | cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
268 | hi, hi_size, 1000 /* FIXME: arbitrary */); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Get device's information (CDID) associated to CHID | ||
273 | * | ||
274 | * The device will return it's information (CDID, name, bandgroups) | ||
275 | * associated to the CHID we have set before, or 0 CDID and default | ||
276 | * name and bandgroup if no CHID set or unknown. | ||
277 | */ | ||
278 | static int cbaf_cdid_get(struct cbaf *cbaf) | ||
279 | { | ||
280 | int result; | ||
281 | struct device *dev = &cbaf->usb_iface->dev; | ||
282 | struct wusb_cbaf_device_info *di; | ||
283 | size_t needed; | ||
284 | |||
285 | di = cbaf->buffer; | ||
286 | result = usb_control_msg( | ||
287 | cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), | ||
288 | CBAF_REQ_GET_ASSOCIATION_REQUEST, | ||
289 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
290 | 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
291 | di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); | ||
292 | if (result < 0) { | ||
293 | dev_err(dev, "Cannot request device information: %d\n", result); | ||
294 | return result; | ||
295 | } | ||
296 | |||
297 | needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length); | ||
298 | if (result < needed) { | ||
299 | dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs " | ||
300 | "%zu bytes needed)\n", (size_t)result, needed); | ||
301 | return result; | ||
302 | } | ||
303 | |||
304 | strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN); | ||
305 | cbaf->cdid = di->CDID; | ||
306 | cbaf->device_band_groups = le16_to_cpu(di->BandGroups); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static ssize_t cbaf_wusb_chid_show(struct device *dev, | ||
312 | struct device_attribute *attr, | ||
313 | char *buf) | ||
314 | { | ||
315 | struct usb_interface *iface = to_usb_interface(dev); | ||
316 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
317 | char pr_chid[WUSB_CKHDID_STRSIZE]; | ||
318 | |||
319 | ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); | ||
320 | return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); | ||
321 | } | ||
322 | |||
323 | static ssize_t cbaf_wusb_chid_store(struct device *dev, | ||
324 | struct device_attribute *attr, | ||
325 | const char *buf, size_t size) | ||
326 | { | ||
327 | ssize_t result; | ||
328 | struct usb_interface *iface = to_usb_interface(dev); | ||
329 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
330 | |||
331 | result = sscanf(buf, | ||
332 | "%02hhx %02hhx %02hhx %02hhx " | ||
333 | "%02hhx %02hhx %02hhx %02hhx " | ||
334 | "%02hhx %02hhx %02hhx %02hhx " | ||
335 | "%02hhx %02hhx %02hhx %02hhx", | ||
336 | &cbaf->chid.data[0] , &cbaf->chid.data[1], | ||
337 | &cbaf->chid.data[2] , &cbaf->chid.data[3], | ||
338 | &cbaf->chid.data[4] , &cbaf->chid.data[5], | ||
339 | &cbaf->chid.data[6] , &cbaf->chid.data[7], | ||
340 | &cbaf->chid.data[8] , &cbaf->chid.data[9], | ||
341 | &cbaf->chid.data[10], &cbaf->chid.data[11], | ||
342 | &cbaf->chid.data[12], &cbaf->chid.data[13], | ||
343 | &cbaf->chid.data[14], &cbaf->chid.data[15]); | ||
344 | |||
345 | if (result != 16) | ||
346 | return -EINVAL; | ||
347 | |||
348 | result = cbaf_send_host_info(cbaf); | ||
349 | if (result < 0) | ||
350 | return result; | ||
351 | result = cbaf_cdid_get(cbaf); | ||
352 | if (result < 0) | ||
353 | return -result; | ||
354 | return size; | ||
355 | } | ||
356 | static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store); | ||
357 | |||
358 | static ssize_t cbaf_wusb_host_name_show(struct device *dev, | ||
359 | struct device_attribute *attr, | ||
360 | char *buf) | ||
361 | { | ||
362 | struct usb_interface *iface = to_usb_interface(dev); | ||
363 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
364 | |||
365 | return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name); | ||
366 | } | ||
367 | |||
368 | static ssize_t cbaf_wusb_host_name_store(struct device *dev, | ||
369 | struct device_attribute *attr, | ||
370 | const char *buf, size_t size) | ||
371 | { | ||
372 | ssize_t result; | ||
373 | struct usb_interface *iface = to_usb_interface(dev); | ||
374 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
375 | |||
376 | result = sscanf(buf, "%63s", cbaf->host_name); | ||
377 | if (result != 1) | ||
378 | return -EINVAL; | ||
379 | |||
380 | return size; | ||
381 | } | ||
382 | static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show, | ||
383 | cbaf_wusb_host_name_store); | ||
384 | |||
385 | static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev, | ||
386 | struct device_attribute *attr, | ||
387 | char *buf) | ||
388 | { | ||
389 | struct usb_interface *iface = to_usb_interface(dev); | ||
390 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
391 | |||
392 | return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups); | ||
393 | } | ||
394 | |||
395 | static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev, | ||
396 | struct device_attribute *attr, | ||
397 | const char *buf, size_t size) | ||
398 | { | ||
399 | ssize_t result; | ||
400 | struct usb_interface *iface = to_usb_interface(dev); | ||
401 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
402 | u16 band_groups = 0; | ||
403 | |||
404 | result = sscanf(buf, "%04hx", &band_groups); | ||
405 | if (result != 1) | ||
406 | return -EINVAL; | ||
407 | |||
408 | cbaf->host_band_groups = band_groups; | ||
409 | |||
410 | return size; | ||
411 | } | ||
412 | |||
413 | static DEVICE_ATTR(wusb_host_band_groups, 0600, | ||
414 | cbaf_wusb_host_band_groups_show, | ||
415 | cbaf_wusb_host_band_groups_store); | ||
416 | |||
417 | static const struct wusb_cbaf_device_info cbaf_device_info_defaults = { | ||
418 | .Length_hdr = WUSB_AR_Length, | ||
419 | .CDID_hdr = WUSB_AR_CDID, | ||
420 | .BandGroups_hdr = WUSB_AR_BandGroups, | ||
421 | .LangID_hdr = WUSB_AR_LangID, | ||
422 | .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName, | ||
423 | }; | ||
424 | |||
425 | static ssize_t cbaf_wusb_cdid_show(struct device *dev, | ||
426 | struct device_attribute *attr, char *buf) | ||
427 | { | ||
428 | struct usb_interface *iface = to_usb_interface(dev); | ||
429 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
430 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
431 | |||
432 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); | ||
433 | return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); | ||
434 | } | ||
435 | |||
436 | static ssize_t cbaf_wusb_cdid_store(struct device *dev, | ||
437 | struct device_attribute *attr, | ||
438 | const char *buf, size_t size) | ||
439 | { | ||
440 | ssize_t result; | ||
441 | struct usb_interface *iface = to_usb_interface(dev); | ||
442 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
443 | struct wusb_ckhdid cdid; | ||
444 | |||
445 | result = sscanf(buf, | ||
446 | "%02hhx %02hhx %02hhx %02hhx " | ||
447 | "%02hhx %02hhx %02hhx %02hhx " | ||
448 | "%02hhx %02hhx %02hhx %02hhx " | ||
449 | "%02hhx %02hhx %02hhx %02hhx", | ||
450 | &cdid.data[0] , &cdid.data[1], | ||
451 | &cdid.data[2] , &cdid.data[3], | ||
452 | &cdid.data[4] , &cdid.data[5], | ||
453 | &cdid.data[6] , &cdid.data[7], | ||
454 | &cdid.data[8] , &cdid.data[9], | ||
455 | &cdid.data[10], &cdid.data[11], | ||
456 | &cdid.data[12], &cdid.data[13], | ||
457 | &cdid.data[14], &cdid.data[15]); | ||
458 | if (result != 16) | ||
459 | return -EINVAL; | ||
460 | |||
461 | cbaf->cdid = cdid; | ||
462 | |||
463 | return size; | ||
464 | } | ||
465 | static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store); | ||
466 | |||
467 | static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev, | ||
468 | struct device_attribute *attr, | ||
469 | char *buf) | ||
470 | { | ||
471 | struct usb_interface *iface = to_usb_interface(dev); | ||
472 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
473 | |||
474 | return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups); | ||
475 | } | ||
476 | |||
477 | static DEVICE_ATTR(wusb_device_band_groups, 0600, | ||
478 | cbaf_wusb_device_band_groups_show, | ||
479 | NULL); | ||
480 | |||
481 | static ssize_t cbaf_wusb_device_name_show(struct device *dev, | ||
482 | struct device_attribute *attr, | ||
483 | char *buf) | ||
484 | { | ||
485 | struct usb_interface *iface = to_usb_interface(dev); | ||
486 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
487 | |||
488 | return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name); | ||
489 | } | ||
490 | static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL); | ||
491 | |||
492 | static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = { | ||
493 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
494 | .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), | ||
495 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
496 | .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE), | ||
497 | .Length_hdr = WUSB_AR_Length, | ||
498 | .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)), | ||
499 | .ConnectionContext_hdr = WUSB_AR_ConnectionContext, | ||
500 | .BandGroups_hdr = WUSB_AR_BandGroups, | ||
501 | }; | ||
502 | |||
503 | static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = { | ||
504 | .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, | ||
505 | .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, | ||
506 | .Length_hdr = WUSB_AR_Length, | ||
507 | .AssociationStatus_hdr = WUSB_AR_AssociationStatus, | ||
508 | }; | ||
509 | |||
510 | /* | ||
511 | * Send a new CC to the device. | ||
512 | */ | ||
513 | static int cbaf_cc_upload(struct cbaf *cbaf) | ||
514 | { | ||
515 | int result; | ||
516 | struct device *dev = &cbaf->usb_iface->dev; | ||
517 | struct wusb_cbaf_cc_data *ccd; | ||
518 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
519 | |||
520 | ccd = cbaf->buffer; | ||
521 | *ccd = cbaf_cc_data_defaults; | ||
522 | ccd->CHID = cbaf->chid; | ||
523 | ccd->CDID = cbaf->cdid; | ||
524 | ccd->CK = cbaf->ck; | ||
525 | ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); | ||
526 | |||
527 | dev_dbg(dev, "Trying to upload CC:\n"); | ||
528 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); | ||
529 | dev_dbg(dev, " CHID %s\n", pr_cdid); | ||
530 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); | ||
531 | dev_dbg(dev, " CDID %s\n", pr_cdid); | ||
532 | dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); | ||
533 | |||
534 | result = usb_control_msg( | ||
535 | cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), | ||
536 | CBAF_REQ_SET_ASSOCIATION_RESPONSE, | ||
537 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
538 | 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
539 | ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */); | ||
540 | |||
541 | return result; | ||
542 | } | ||
543 | |||
544 | static ssize_t cbaf_wusb_ck_store(struct device *dev, | ||
545 | struct device_attribute *attr, | ||
546 | const char *buf, size_t size) | ||
547 | { | ||
548 | ssize_t result; | ||
549 | struct usb_interface *iface = to_usb_interface(dev); | ||
550 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
551 | |||
552 | result = sscanf(buf, | ||
553 | "%02hhx %02hhx %02hhx %02hhx " | ||
554 | "%02hhx %02hhx %02hhx %02hhx " | ||
555 | "%02hhx %02hhx %02hhx %02hhx " | ||
556 | "%02hhx %02hhx %02hhx %02hhx", | ||
557 | &cbaf->ck.data[0] , &cbaf->ck.data[1], | ||
558 | &cbaf->ck.data[2] , &cbaf->ck.data[3], | ||
559 | &cbaf->ck.data[4] , &cbaf->ck.data[5], | ||
560 | &cbaf->ck.data[6] , &cbaf->ck.data[7], | ||
561 | &cbaf->ck.data[8] , &cbaf->ck.data[9], | ||
562 | &cbaf->ck.data[10], &cbaf->ck.data[11], | ||
563 | &cbaf->ck.data[12], &cbaf->ck.data[13], | ||
564 | &cbaf->ck.data[14], &cbaf->ck.data[15]); | ||
565 | if (result != 16) | ||
566 | return -EINVAL; | ||
567 | |||
568 | result = cbaf_cc_upload(cbaf); | ||
569 | if (result < 0) | ||
570 | return result; | ||
571 | |||
572 | return size; | ||
573 | } | ||
574 | static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store); | ||
575 | |||
576 | static struct attribute *cbaf_dev_attrs[] = { | ||
577 | &dev_attr_wusb_host_name.attr, | ||
578 | &dev_attr_wusb_host_band_groups.attr, | ||
579 | &dev_attr_wusb_chid.attr, | ||
580 | &dev_attr_wusb_cdid.attr, | ||
581 | &dev_attr_wusb_device_name.attr, | ||
582 | &dev_attr_wusb_device_band_groups.attr, | ||
583 | &dev_attr_wusb_ck.attr, | ||
584 | NULL, | ||
585 | }; | ||
586 | |||
587 | static struct attribute_group cbaf_dev_attr_group = { | ||
588 | .name = NULL, /* we want them in the same directory */ | ||
589 | .attrs = cbaf_dev_attrs, | ||
590 | }; | ||
591 | |||
592 | static int cbaf_probe(struct usb_interface *iface, | ||
593 | const struct usb_device_id *id) | ||
594 | { | ||
595 | struct cbaf *cbaf; | ||
596 | struct device *dev = &iface->dev; | ||
597 | int result = -ENOMEM; | ||
598 | |||
599 | cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL); | ||
600 | if (cbaf == NULL) | ||
601 | goto error_kzalloc; | ||
602 | cbaf->buffer = kmalloc(512, GFP_KERNEL); | ||
603 | if (cbaf->buffer == NULL) | ||
604 | goto error_kmalloc_buffer; | ||
605 | |||
606 | cbaf->buffer_size = 512; | ||
607 | cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface)); | ||
608 | cbaf->usb_iface = usb_get_intf(iface); | ||
609 | result = cbaf_check(cbaf); | ||
610 | if (result < 0) { | ||
611 | dev_err(dev, "This device is not WUSB-CBAF compliant" | ||
612 | "and is not supported yet.\n"); | ||
613 | goto error_check; | ||
614 | } | ||
615 | |||
616 | result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group); | ||
617 | if (result < 0) { | ||
618 | dev_err(dev, "Can't register sysfs attr group: %d\n", result); | ||
619 | goto error_create_group; | ||
620 | } | ||
621 | usb_set_intfdata(iface, cbaf); | ||
622 | return 0; | ||
623 | |||
624 | error_create_group: | ||
625 | error_check: | ||
626 | kfree(cbaf->buffer); | ||
627 | error_kmalloc_buffer: | ||
628 | kfree(cbaf); | ||
629 | error_kzalloc: | ||
630 | return result; | ||
631 | } | ||
632 | |||
633 | static void cbaf_disconnect(struct usb_interface *iface) | ||
634 | { | ||
635 | struct cbaf *cbaf = usb_get_intfdata(iface); | ||
636 | struct device *dev = &iface->dev; | ||
637 | sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group); | ||
638 | usb_set_intfdata(iface, NULL); | ||
639 | usb_put_intf(iface); | ||
640 | kfree(cbaf->buffer); | ||
641 | /* paranoia: clean up crypto keys */ | ||
642 | memset(cbaf, 0, sizeof(*cbaf)); | ||
643 | kfree(cbaf); | ||
644 | } | ||
645 | |||
646 | static struct usb_device_id cbaf_id_table[] = { | ||
647 | { USB_INTERFACE_INFO(0xef, 0x03, 0x01), }, | ||
648 | { }, | ||
649 | }; | ||
650 | MODULE_DEVICE_TABLE(usb, cbaf_id_table); | ||
651 | |||
652 | static struct usb_driver cbaf_driver = { | ||
653 | .name = "wusb-cbaf", | ||
654 | .id_table = cbaf_id_table, | ||
655 | .probe = cbaf_probe, | ||
656 | .disconnect = cbaf_disconnect, | ||
657 | }; | ||
658 | |||
659 | static int __init cbaf_driver_init(void) | ||
660 | { | ||
661 | return usb_register(&cbaf_driver); | ||
662 | } | ||
663 | module_init(cbaf_driver_init); | ||
664 | |||
665 | static void __exit cbaf_driver_exit(void) | ||
666 | { | ||
667 | usb_deregister(&cbaf_driver); | ||
668 | } | ||
669 | module_exit(cbaf_driver_exit); | ||
670 | |||
671 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
672 | MODULE_DESCRIPTION("Wireless USB Cable Based Association"); | ||
673 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c new file mode 100644 index 000000000000..c36c4389baae --- /dev/null +++ b/drivers/usb/wusbcore/crypto.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * AES-128 CCM Encryption | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * We don't do any encryption here; we use the Linux Kernel's AES-128 | ||
24 | * crypto modules to construct keys and payload blocks in a way | ||
25 | * defined by WUSB1.0[6]. Check the erratas, as typos are are patched | ||
26 | * there. | ||
27 | * | ||
28 | * Thanks a zillion to John Keys for his help and clarifications over | ||
29 | * the designed-by-a-committee text. | ||
30 | * | ||
31 | * So the idea is that there is this basic Pseudo-Random-Function | ||
32 | * defined in WUSB1.0[6.5] which is the core of everything. It works | ||
33 | * by tweaking some blocks, AES crypting them and then xoring | ||
34 | * something else with them (this seems to be called CBC(AES) -- can | ||
35 | * you tell I know jack about crypto?). So we just funnel it into the | ||
36 | * Linux Crypto API. | ||
37 | * | ||
38 | * We leave a crypto test module so we can verify that vectors match, | ||
39 | * every now and then. | ||
40 | * | ||
41 | * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I | ||
42 | * am learning a lot... | ||
43 | * | ||
44 | * Conveniently, some data structures that need to be | ||
45 | * funneled through AES are...16 bytes in size! | ||
46 | */ | ||
47 | |||
48 | #include <linux/crypto.h> | ||
49 | #include <linux/module.h> | ||
50 | #include <linux/err.h> | ||
51 | #include <linux/uwb.h> | ||
52 | #include <linux/usb/wusb.h> | ||
53 | #include <linux/scatterlist.h> | ||
54 | #define D_LOCAL 0 | ||
55 | #include <linux/uwb/debug.h> | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Block of data, as understood by AES-CCM | ||
60 | * | ||
61 | * The code assumes this structure is nothing but a 16 byte array | ||
62 | * (packed in a struct to avoid common mess ups that I usually do with | ||
63 | * arrays and enforcing type checking). | ||
64 | */ | ||
65 | struct aes_ccm_block { | ||
66 | u8 data[16]; | ||
67 | } __attribute__((packed)); | ||
68 | |||
69 | /* | ||
70 | * Counter-mode Blocks (WUSB1.0[6.4]) | ||
71 | * | ||
72 | * According to CCM (or so it seems), for the purpose of calculating | ||
73 | * the MIC, the message is broken in N counter-mode blocks, B0, B1, | ||
74 | * ... BN. | ||
75 | * | ||
76 | * B0 contains flags, the CCM nonce and l(m). | ||
77 | * | ||
78 | * B1 contains l(a), the MAC header, the encryption offset and padding. | ||
79 | * | ||
80 | * If EO is nonzero, additional blocks are built from payload bytes | ||
81 | * until EO is exahusted (FIXME: padding to 16 bytes, I guess). The | ||
82 | * padding is not xmitted. | ||
83 | */ | ||
84 | |||
85 | /* WUSB1.0[T6.4] */ | ||
86 | struct aes_ccm_b0 { | ||
87 | u8 flags; /* 0x59, per CCM spec */ | ||
88 | struct aes_ccm_nonce ccm_nonce; | ||
89 | __be16 lm; | ||
90 | } __attribute__((packed)); | ||
91 | |||
92 | /* WUSB1.0[T6.5] */ | ||
93 | struct aes_ccm_b1 { | ||
94 | __be16 la; | ||
95 | u8 mac_header[10]; | ||
96 | __le16 eo; | ||
97 | u8 security_reserved; /* This is always zero */ | ||
98 | u8 padding; /* 0 */ | ||
99 | } __attribute__((packed)); | ||
100 | |||
101 | /* | ||
102 | * Encryption Blocks (WUSB1.0[6.4.4]) | ||
103 | * | ||
104 | * CCM uses Ax blocks to generate a keystream with which the MIC and | ||
105 | * the message's payload are encoded. A0 always encrypts/decrypts the | ||
106 | * MIC. Ax (x>0) are used for the sucesive payload blocks. | ||
107 | * | ||
108 | * The x is the counter, and is increased for each block. | ||
109 | */ | ||
110 | struct aes_ccm_a { | ||
111 | u8 flags; /* 0x01, per CCM spec */ | ||
112 | struct aes_ccm_nonce ccm_nonce; | ||
113 | __be16 counter; /* Value of x */ | ||
114 | } __attribute__((packed)); | ||
115 | |||
116 | static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, | ||
117 | size_t size) | ||
118 | { | ||
119 | u8 *bo = _bo; | ||
120 | const u8 *bi1 = _bi1, *bi2 = _bi2; | ||
121 | size_t itr; | ||
122 | for (itr = 0; itr < size; itr++) | ||
123 | bo[itr] = bi1[itr] ^ bi2[itr]; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * CC-MAC function WUSB1.0[6.5] | ||
128 | * | ||
129 | * Take a data string and produce the encrypted CBC Counter-mode MIC | ||
130 | * | ||
131 | * Note the names for most function arguments are made to (more or | ||
132 | * less) match those used in the pseudo-function definition given in | ||
133 | * WUSB1.0[6.5]. | ||
134 | * | ||
135 | * @tfm_cbc: CBC(AES) blkcipher handle (initialized) | ||
136 | * | ||
137 | * @tfm_aes: AES cipher handle (initialized) | ||
138 | * | ||
139 | * @mic: buffer for placing the computed MIC (Message Integrity | ||
140 | * Code). This is exactly 8 bytes, and we expect the buffer to | ||
141 | * be at least eight bytes in length. | ||
142 | * | ||
143 | * @key: 128 bit symmetric key | ||
144 | * | ||
145 | * @n: CCM nonce | ||
146 | * | ||
147 | * @a: ASCII string, 14 bytes long (I guess zero padded if needed; | ||
148 | * we use exactly 14 bytes). | ||
149 | * | ||
150 | * @b: data stream to be processed; cannot be a global or const local | ||
151 | * (will confuse the scatterlists) | ||
152 | * | ||
153 | * @blen: size of b... | ||
154 | * | ||
155 | * Still not very clear how this is done, but looks like this: we | ||
156 | * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with | ||
157 | * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we | ||
158 | * take the payload and divide it in blocks (16 bytes), xor them with | ||
159 | * the previous crypto result (16 bytes) and crypt it, repeat the next | ||
160 | * block with the output of the previous one, rinse wash (I guess this | ||
161 | * is what AES CBC mode means...but I truly have no idea). So we use | ||
162 | * the CBC(AES) blkcipher, that does precisely that. The IV (Initial | ||
163 | * Vector) is 16 bytes and is set to zero, so | ||
164 | * | ||
165 | * See rfc3610. Linux crypto has a CBC implementation, but the | ||
166 | * documentation is scarce, to say the least, and the example code is | ||
167 | * so intricated that is difficult to understand how things work. Most | ||
168 | * of this is guess work -- bite me. | ||
169 | * | ||
170 | * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and | ||
171 | * using the 14 bytes of @a to fill up | ||
172 | * b1.{mac_header,e0,security_reserved,padding}. | ||
173 | * | ||
174 | * NOTE: The definiton of l(a) in WUSB1.0[6.5] vs the definition of | ||
175 | * l(m) is orthogonal, they bear no relationship, so it is not | ||
176 | * in conflict with the parameter's relation that | ||
177 | * WUSB1.0[6.4.2]) defines. | ||
178 | * | ||
179 | * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in | ||
180 | * first errata released on 2005/07. | ||
181 | * | ||
182 | * NOTE: we need to clean IV to zero at each invocation to make sure | ||
183 | * we start with a fresh empty Initial Vector, so that the CBC | ||
184 | * works ok. | ||
185 | * | ||
186 | * NOTE: blen is not aligned to a block size, we'll pad zeros, that's | ||
187 | * what sg[4] is for. Maybe there is a smarter way to do this. | ||
188 | */ | ||
189 | static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, | ||
190 | struct crypto_cipher *tfm_aes, void *mic, | ||
191 | const struct aes_ccm_nonce *n, | ||
192 | const struct aes_ccm_label *a, const void *b, | ||
193 | size_t blen) | ||
194 | { | ||
195 | int result = 0; | ||
196 | struct blkcipher_desc desc; | ||
197 | struct aes_ccm_b0 b0; | ||
198 | struct aes_ccm_b1 b1; | ||
199 | struct aes_ccm_a ax; | ||
200 | struct scatterlist sg[4], sg_dst; | ||
201 | void *iv, *dst_buf; | ||
202 | size_t ivsize, dst_size; | ||
203 | const u8 bzero[16] = { 0 }; | ||
204 | size_t zero_padding; | ||
205 | |||
206 | d_fnstart(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " | ||
207 | "n %p, a %p, b %p, blen %zu)\n", | ||
208 | tfm_cbc, tfm_aes, mic, n, a, b, blen); | ||
209 | /* | ||
210 | * These checks should be compile time optimized out | ||
211 | * ensure @a fills b1's mac_header and following fields | ||
212 | */ | ||
213 | WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); | ||
214 | WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); | ||
215 | WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); | ||
216 | WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); | ||
217 | |||
218 | result = -ENOMEM; | ||
219 | zero_padding = sizeof(struct aes_ccm_block) | ||
220 | - blen % sizeof(struct aes_ccm_block); | ||
221 | zero_padding = blen % sizeof(struct aes_ccm_block); | ||
222 | if (zero_padding) | ||
223 | zero_padding = sizeof(struct aes_ccm_block) - zero_padding; | ||
224 | dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; | ||
225 | dst_buf = kzalloc(dst_size, GFP_KERNEL); | ||
226 | if (dst_buf == NULL) { | ||
227 | printk(KERN_ERR "E: can't alloc destination buffer\n"); | ||
228 | goto error_dst_buf; | ||
229 | } | ||
230 | |||
231 | iv = crypto_blkcipher_crt(tfm_cbc)->iv; | ||
232 | ivsize = crypto_blkcipher_ivsize(tfm_cbc); | ||
233 | memset(iv, 0, ivsize); | ||
234 | |||
235 | /* Setup B0 */ | ||
236 | b0.flags = 0x59; /* Format B0 */ | ||
237 | b0.ccm_nonce = *n; | ||
238 | b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ | ||
239 | |||
240 | /* Setup B1 | ||
241 | * | ||
242 | * The WUSB spec is anything but clear! WUSB1.0[6.5] | ||
243 | * says that to initialize B1 from A with 'l(a) = blen + | ||
244 | * 14'--after clarification, it means to use A's contents | ||
245 | * for MAC Header, EO, sec reserved and padding. | ||
246 | */ | ||
247 | b1.la = cpu_to_be16(blen + 14); | ||
248 | memcpy(&b1.mac_header, a, sizeof(*a)); | ||
249 | |||
250 | d_printf(4, NULL, "I: B0 (%zu bytes)\n", sizeof(b0)); | ||
251 | d_dump(4, NULL, &b0, sizeof(b0)); | ||
252 | d_printf(4, NULL, "I: B1 (%zu bytes)\n", sizeof(b1)); | ||
253 | d_dump(4, NULL, &b1, sizeof(b1)); | ||
254 | d_printf(4, NULL, "I: B (%zu bytes)\n", blen); | ||
255 | d_dump(4, NULL, b, blen); | ||
256 | d_printf(4, NULL, "I: B 0-padding (%zu bytes)\n", zero_padding); | ||
257 | d_printf(4, NULL, "D: IV before crypto (%zu)\n", ivsize); | ||
258 | d_dump(4, NULL, iv, ivsize); | ||
259 | |||
260 | sg_init_table(sg, ARRAY_SIZE(sg)); | ||
261 | sg_set_buf(&sg[0], &b0, sizeof(b0)); | ||
262 | sg_set_buf(&sg[1], &b1, sizeof(b1)); | ||
263 | sg_set_buf(&sg[2], b, blen); | ||
264 | /* 0 if well behaved :) */ | ||
265 | sg_set_buf(&sg[3], bzero, zero_padding); | ||
266 | sg_init_one(&sg_dst, dst_buf, dst_size); | ||
267 | |||
268 | desc.tfm = tfm_cbc; | ||
269 | desc.flags = 0; | ||
270 | result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size); | ||
271 | if (result < 0) { | ||
272 | printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", | ||
273 | result); | ||
274 | goto error_cbc_crypt; | ||
275 | } | ||
276 | d_printf(4, NULL, "D: MIC tag\n"); | ||
277 | d_dump(4, NULL, iv, ivsize); | ||
278 | |||
279 | /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] | ||
280 | * The procedure is to AES crypt the A0 block and XOR the MIC | ||
281 | * Tag agains it; we only do the first 8 bytes and place it | ||
282 | * directly in the destination buffer. | ||
283 | * | ||
284 | * POS Crypto API: size is assumed to be AES's block size. | ||
285 | * Thanks for documenting it -- tip taken from airo.c | ||
286 | */ | ||
287 | ax.flags = 0x01; /* as per WUSB 1.0 spec */ | ||
288 | ax.ccm_nonce = *n; | ||
289 | ax.counter = 0; | ||
290 | crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); | ||
291 | bytewise_xor(mic, &ax, iv, 8); | ||
292 | d_printf(4, NULL, "D: CTR[MIC]\n"); | ||
293 | d_dump(4, NULL, &ax, 8); | ||
294 | d_printf(4, NULL, "D: CCM-MIC tag\n"); | ||
295 | d_dump(4, NULL, mic, 8); | ||
296 | result = 8; | ||
297 | error_cbc_crypt: | ||
298 | kfree(dst_buf); | ||
299 | error_dst_buf: | ||
300 | d_fnend(3, NULL, "(tfm_cbc %p, tfm_aes %p, mic %p, " | ||
301 | "n %p, a %p, b %p, blen %zu)\n", | ||
302 | tfm_cbc, tfm_aes, mic, n, a, b, blen); | ||
303 | return result; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * WUSB Pseudo Random Function (WUSB1.0[6.5]) | ||
308 | * | ||
309 | * @b: buffer to the source data; cannot be a global or const local | ||
310 | * (will confuse the scatterlists) | ||
311 | */ | ||
312 | ssize_t wusb_prf(void *out, size_t out_size, | ||
313 | const u8 key[16], const struct aes_ccm_nonce *_n, | ||
314 | const struct aes_ccm_label *a, | ||
315 | const void *b, size_t blen, size_t len) | ||
316 | { | ||
317 | ssize_t result, bytes = 0, bitr; | ||
318 | struct aes_ccm_nonce n = *_n; | ||
319 | struct crypto_blkcipher *tfm_cbc; | ||
320 | struct crypto_cipher *tfm_aes; | ||
321 | u64 sfn = 0; | ||
322 | __le64 sfn_le; | ||
323 | |||
324 | d_fnstart(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " | ||
325 | "a %p, b %p, blen %zu, len %zu)\n", out, out_size, | ||
326 | key, _n, a, b, blen, len); | ||
327 | |||
328 | tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); | ||
329 | if (IS_ERR(tfm_cbc)) { | ||
330 | result = PTR_ERR(tfm_cbc); | ||
331 | printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result); | ||
332 | goto error_alloc_cbc; | ||
333 | } | ||
334 | result = crypto_blkcipher_setkey(tfm_cbc, key, 16); | ||
335 | if (result < 0) { | ||
336 | printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result); | ||
337 | goto error_setkey_cbc; | ||
338 | } | ||
339 | |||
340 | tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | ||
341 | if (IS_ERR(tfm_aes)) { | ||
342 | result = PTR_ERR(tfm_aes); | ||
343 | printk(KERN_ERR "E: can't load AES: %d\n", (int)result); | ||
344 | goto error_alloc_aes; | ||
345 | } | ||
346 | result = crypto_cipher_setkey(tfm_aes, key, 16); | ||
347 | if (result < 0) { | ||
348 | printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); | ||
349 | goto error_setkey_aes; | ||
350 | } | ||
351 | |||
352 | for (bitr = 0; bitr < (len + 63) / 64; bitr++) { | ||
353 | sfn_le = cpu_to_le64(sfn++); | ||
354 | memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ | ||
355 | result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes, | ||
356 | &n, a, b, blen); | ||
357 | if (result < 0) | ||
358 | goto error_ccm_mac; | ||
359 | bytes += result; | ||
360 | } | ||
361 | result = bytes; | ||
362 | error_ccm_mac: | ||
363 | error_setkey_aes: | ||
364 | crypto_free_cipher(tfm_aes); | ||
365 | error_alloc_aes: | ||
366 | error_setkey_cbc: | ||
367 | crypto_free_blkcipher(tfm_cbc); | ||
368 | error_alloc_cbc: | ||
369 | d_fnend(3, NULL, "(out %p, out_size %zu, key %p, _n %p, " | ||
370 | "a %p, b %p, blen %zu, len %zu) = %d\n", out, out_size, | ||
371 | key, _n, a, b, blen, len, (int)bytes); | ||
372 | return result; | ||
373 | } | ||
374 | |||
375 | /* WUSB1.0[A.2] test vectors */ | ||
376 | static const u8 stv_hsmic_key[16] = { | ||
377 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | ||
378 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | ||
379 | }; | ||
380 | |||
381 | static const struct aes_ccm_nonce stv_hsmic_n = { | ||
382 | .sfn = { 0 }, | ||
383 | .tkid = { 0x76, 0x98, 0x01, }, | ||
384 | .dest_addr = { .data = { 0xbe, 0x00 } }, | ||
385 | .src_addr = { .data = { 0x76, 0x98 } }, | ||
386 | }; | ||
387 | |||
388 | /* | ||
389 | * Out-of-band MIC Generation verification code | ||
390 | * | ||
391 | */ | ||
392 | static int wusb_oob_mic_verify(void) | ||
393 | { | ||
394 | int result; | ||
395 | u8 mic[8]; | ||
396 | /* WUSB1.0[A.2] test vectors | ||
397 | * | ||
398 | * Need to keep it in the local stack as GCC 4.1.3something | ||
399 | * messes up and generates noise. | ||
400 | */ | ||
401 | struct usb_handshake stv_hsmic_hs = { | ||
402 | .bMessageNumber = 2, | ||
403 | .bStatus = 00, | ||
404 | .tTKID = { 0x76, 0x98, 0x01 }, | ||
405 | .bReserved = 00, | ||
406 | .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | ||
407 | 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, | ||
408 | 0x3c, 0x3d, 0x3e, 0x3f }, | ||
409 | .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, | ||
410 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, | ||
411 | 0x2c, 0x2d, 0x2e, 0x2f }, | ||
412 | .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c, | ||
413 | 0x14, 0x7b } , | ||
414 | }; | ||
415 | size_t hs_size; | ||
416 | |||
417 | result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs); | ||
418 | if (result < 0) | ||
419 | printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result); | ||
420 | else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) { | ||
421 | printk(KERN_ERR "E: OOB MIC test: " | ||
422 | "mismatch between MIC result and WUSB1.0[A2]\n"); | ||
423 | hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC); | ||
424 | printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size); | ||
425 | dump_bytes(NULL, &stv_hsmic_hs, hs_size); | ||
426 | printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n", | ||
427 | sizeof(stv_hsmic_n)); | ||
428 | dump_bytes(NULL, &stv_hsmic_n, sizeof(stv_hsmic_n)); | ||
429 | printk(KERN_ERR "E: MIC out:\n"); | ||
430 | dump_bytes(NULL, mic, sizeof(mic)); | ||
431 | printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n"); | ||
432 | dump_bytes(NULL, stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); | ||
433 | result = -EINVAL; | ||
434 | } else | ||
435 | result = 0; | ||
436 | return result; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * Test vectors for Key derivation | ||
441 | * | ||
442 | * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1] | ||
443 | * (errata corrected in 2005/07). | ||
444 | */ | ||
445 | static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = { | ||
446 | 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, | ||
447 | 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f | ||
448 | }; | ||
449 | |||
450 | static const struct aes_ccm_nonce stv_keydvt_n_a1 = { | ||
451 | .sfn = { 0 }, | ||
452 | .tkid = { 0x76, 0x98, 0x01, }, | ||
453 | .dest_addr = { .data = { 0xbe, 0x00 } }, | ||
454 | .src_addr = { .data = { 0x76, 0x98 } }, | ||
455 | }; | ||
456 | |||
457 | static const struct wusb_keydvt_out stv_keydvt_out_a1 = { | ||
458 | .kck = { | ||
459 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | ||
460 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | ||
461 | }, | ||
462 | .ptk = { | ||
463 | 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06, | ||
464 | 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d | ||
465 | } | ||
466 | }; | ||
467 | |||
468 | /* | ||
469 | * Performa a test to make sure we match the vectors defined in | ||
470 | * WUSB1.0[A.1](Errata2006/12) | ||
471 | */ | ||
472 | static int wusb_key_derive_verify(void) | ||
473 | { | ||
474 | int result = 0; | ||
475 | struct wusb_keydvt_out keydvt_out; | ||
476 | /* These come from WUSB1.0[A.1] + 2006/12 errata | ||
477 | * NOTE: can't make this const or global -- somehow it seems | ||
478 | * the scatterlists for crypto get confused and we get | ||
479 | * bad data. There is no doc on this... */ | ||
480 | struct wusb_keydvt_in stv_keydvt_in_a1 = { | ||
481 | .hnonce = { | ||
482 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
483 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f | ||
484 | }, | ||
485 | .dnonce = { | ||
486 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
487 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f | ||
488 | } | ||
489 | }; | ||
490 | |||
491 | result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1, | ||
492 | &stv_keydvt_in_a1); | ||
493 | if (result < 0) | ||
494 | printk(KERN_ERR "E: WUSB key derivation test: " | ||
495 | "derivation failed: %d\n", result); | ||
496 | if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) { | ||
497 | printk(KERN_ERR "E: WUSB key derivation test: " | ||
498 | "mismatch between key derivation result " | ||
499 | "and WUSB1.0[A1] Errata 2006/12\n"); | ||
500 | printk(KERN_ERR "E: keydvt in: key (%zu bytes)\n", | ||
501 | sizeof(stv_key_a1)); | ||
502 | dump_bytes(NULL, stv_key_a1, sizeof(stv_key_a1)); | ||
503 | printk(KERN_ERR "E: keydvt in: nonce (%zu bytes)\n", | ||
504 | sizeof(stv_keydvt_n_a1)); | ||
505 | dump_bytes(NULL, &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); | ||
506 | printk(KERN_ERR "E: keydvt in: hnonce & dnonce (%zu bytes)\n", | ||
507 | sizeof(stv_keydvt_in_a1)); | ||
508 | dump_bytes(NULL, &stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); | ||
509 | printk(KERN_ERR "E: keydvt out: KCK\n"); | ||
510 | dump_bytes(NULL, &keydvt_out.kck, sizeof(keydvt_out.kck)); | ||
511 | printk(KERN_ERR "E: keydvt out: PTK\n"); | ||
512 | dump_bytes(NULL, &keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
513 | result = -EINVAL; | ||
514 | } else | ||
515 | result = 0; | ||
516 | return result; | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * Initialize crypto system | ||
521 | * | ||
522 | * FIXME: we do nothing now, other than verifying. Later on we'll | ||
523 | * cache the encryption stuff, so that's why we have a separate init. | ||
524 | */ | ||
525 | int wusb_crypto_init(void) | ||
526 | { | ||
527 | int result; | ||
528 | |||
529 | result = wusb_key_derive_verify(); | ||
530 | if (result < 0) | ||
531 | return result; | ||
532 | return wusb_oob_mic_verify(); | ||
533 | } | ||
534 | |||
535 | void wusb_crypto_exit(void) | ||
536 | { | ||
537 | /* FIXME: free cached crypto transforms */ | ||
538 | } | ||
diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c new file mode 100644 index 000000000000..7897a19652e5 --- /dev/null +++ b/drivers/usb/wusbcore/dev-sysfs.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * WUSB devices | ||
3 | * sysfs bindings | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Get them out of the way... | ||
24 | */ | ||
25 | |||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include "wusbhc.h" | ||
30 | |||
31 | #undef D_LOCAL | ||
32 | #define D_LOCAL 4 | ||
33 | #include <linux/uwb/debug.h> | ||
34 | |||
35 | static ssize_t wusb_disconnect_store(struct device *dev, | ||
36 | struct device_attribute *attr, | ||
37 | const char *buf, size_t size) | ||
38 | { | ||
39 | struct usb_device *usb_dev; | ||
40 | struct wusbhc *wusbhc; | ||
41 | unsigned command; | ||
42 | u8 port_idx; | ||
43 | |||
44 | if (sscanf(buf, "%u", &command) != 1) | ||
45 | return -EINVAL; | ||
46 | if (command == 0) | ||
47 | return size; | ||
48 | usb_dev = to_usb_device(dev); | ||
49 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
50 | if (wusbhc == NULL) | ||
51 | return -ENODEV; | ||
52 | |||
53 | mutex_lock(&wusbhc->mutex); | ||
54 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
55 | __wusbhc_dev_disable(wusbhc, port_idx); | ||
56 | mutex_unlock(&wusbhc->mutex); | ||
57 | wusbhc_put(wusbhc); | ||
58 | return size; | ||
59 | } | ||
60 | static DEVICE_ATTR(wusb_disconnect, 0200, NULL, wusb_disconnect_store); | ||
61 | |||
62 | static ssize_t wusb_cdid_show(struct device *dev, | ||
63 | struct device_attribute *attr, char *buf) | ||
64 | { | ||
65 | ssize_t result; | ||
66 | struct wusb_dev *wusb_dev; | ||
67 | |||
68 | wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); | ||
69 | if (wusb_dev == NULL) | ||
70 | return -ENODEV; | ||
71 | result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); | ||
72 | strcat(buf, "\n"); | ||
73 | wusb_dev_put(wusb_dev); | ||
74 | return result + 1; | ||
75 | } | ||
76 | static DEVICE_ATTR(wusb_cdid, 0444, wusb_cdid_show, NULL); | ||
77 | |||
78 | static ssize_t wusb_ck_store(struct device *dev, | ||
79 | struct device_attribute *attr, | ||
80 | const char *buf, size_t size) | ||
81 | { | ||
82 | int result; | ||
83 | struct usb_device *usb_dev; | ||
84 | struct wusbhc *wusbhc; | ||
85 | struct wusb_ckhdid ck; | ||
86 | |||
87 | result = sscanf(buf, | ||
88 | "%02hhx %02hhx %02hhx %02hhx " | ||
89 | "%02hhx %02hhx %02hhx %02hhx " | ||
90 | "%02hhx %02hhx %02hhx %02hhx " | ||
91 | "%02hhx %02hhx %02hhx %02hhx\n", | ||
92 | &ck.data[0] , &ck.data[1], | ||
93 | &ck.data[2] , &ck.data[3], | ||
94 | &ck.data[4] , &ck.data[5], | ||
95 | &ck.data[6] , &ck.data[7], | ||
96 | &ck.data[8] , &ck.data[9], | ||
97 | &ck.data[10], &ck.data[11], | ||
98 | &ck.data[12], &ck.data[13], | ||
99 | &ck.data[14], &ck.data[15]); | ||
100 | if (result != 16) | ||
101 | return -EINVAL; | ||
102 | |||
103 | usb_dev = to_usb_device(dev); | ||
104 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
105 | if (wusbhc == NULL) | ||
106 | return -ENODEV; | ||
107 | result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck); | ||
108 | memset(&ck, 0, sizeof(ck)); | ||
109 | wusbhc_put(wusbhc); | ||
110 | return result < 0 ? result : size; | ||
111 | } | ||
112 | static DEVICE_ATTR(wusb_ck, 0200, NULL, wusb_ck_store); | ||
113 | |||
114 | static struct attribute *wusb_dev_attrs[] = { | ||
115 | &dev_attr_wusb_disconnect.attr, | ||
116 | &dev_attr_wusb_cdid.attr, | ||
117 | &dev_attr_wusb_ck.attr, | ||
118 | NULL, | ||
119 | }; | ||
120 | |||
121 | static struct attribute_group wusb_dev_attr_group = { | ||
122 | .name = NULL, /* we want them in the same directory */ | ||
123 | .attrs = wusb_dev_attrs, | ||
124 | }; | ||
125 | |||
126 | int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev, | ||
127 | struct wusb_dev *wusb_dev) | ||
128 | { | ||
129 | int result = sysfs_create_group(&usb_dev->dev.kobj, | ||
130 | &wusb_dev_attr_group); | ||
131 | struct device *dev = &usb_dev->dev; | ||
132 | if (result < 0) | ||
133 | dev_err(dev, "Cannot register WUSB-dev attributes: %d\n", | ||
134 | result); | ||
135 | return result; | ||
136 | } | ||
137 | |||
138 | void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev) | ||
139 | { | ||
140 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
141 | if (usb_dev) | ||
142 | sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group); | ||
143 | } | ||
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c new file mode 100644 index 000000000000..f45d777bef34 --- /dev/null +++ b/drivers/usb/wusbcore/devconnect.c | |||
@@ -0,0 +1,1297 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * Device Connect handling | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * FIXME: this file needs to be broken up, it's grown too big | ||
25 | * | ||
26 | * | ||
27 | * WUSB1.0[7.1, 7.5.1, ] | ||
28 | * | ||
29 | * WUSB device connection is kind of messy. Some background: | ||
30 | * | ||
31 | * When a device wants to connect it scans the UWB radio channels | ||
32 | * looking for a WUSB Channel; a WUSB channel is defined by MMCs | ||
33 | * (Micro Managed Commands or something like that) [see | ||
34 | * Design-overview for more on this] . | ||
35 | * | ||
36 | * So, device scans the radio, finds MMCs and thus a host and checks | ||
37 | * when the next DNTS is. It sends a Device Notification Connect | ||
38 | * (DN_Connect); the host picks it up (through nep.c and notif.c, ends | ||
39 | * up in wusb_devconnect_ack(), which creates a wusb_dev structure in | ||
40 | * wusbhc->port[port_number].wusb_dev), assigns an unauth address | ||
41 | * to the device (this means from 0x80 to 0xfe) and sends, in the MMC | ||
42 | * a Connect Ack Information Element (ConnAck IE). | ||
43 | * | ||
44 | * So now the device now has a WUSB address. From now on, we use | ||
45 | * that to talk to it in the RPipes. | ||
46 | * | ||
47 | * ASSUMPTIONS: | ||
48 | * | ||
49 | * - We use the the as device address the port number where it is | ||
50 | * connected (port 0 doesn't exist). For unauth, it is 128 + that. | ||
51 | * | ||
52 | * ROADMAP: | ||
53 | * | ||
54 | * This file contains the logic for doing that--entry points: | ||
55 | * | ||
56 | * wusb_devconnect_ack() Ack a device until _acked() called. | ||
57 | * Called by notif.c:wusb_handle_dn_connect() | ||
58 | * when a DN_Connect is received. | ||
59 | * | ||
60 | * wusbhc_devconnect_auth() Called by rh.c:wusbhc_rh_port_reset() when | ||
61 | * doing the device connect sequence. | ||
62 | * | ||
63 | * wusb_devconnect_acked() Ack done, release resources. | ||
64 | * | ||
65 | * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn() | ||
66 | * for processing a DN_Alive pong from a device. | ||
67 | * | ||
68 | * wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to | ||
69 | * process a disconenct request from a | ||
70 | * device. | ||
71 | * | ||
72 | * wusb_dev_reset() Called by rh.c:wusbhc_rh_port_reset() when | ||
73 | * resetting a device. | ||
74 | * | ||
75 | * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when | ||
76 | * disabling a port. | ||
77 | * | ||
78 | * wusb_devconnect_create() Called when creating the host by | ||
79 | * lc.c:wusbhc_create(). | ||
80 | * | ||
81 | * wusb_devconnect_destroy() Cleanup called removing the host. Called | ||
82 | * by lc.c:wusbhc_destroy(). | ||
83 | * | ||
84 | * Each Wireless USB host maintains a list of DN_Connect requests | ||
85 | * (actually we maintain a list of pending Connect Acks, the | ||
86 | * wusbhc->ca_list). | ||
87 | * | ||
88 | * LIFE CYCLE OF port->wusb_dev | ||
89 | * | ||
90 | * Before the @wusbhc structure put()s the reference it owns for | ||
91 | * port->wusb_dev [and clean the wusb_dev pointer], it needs to | ||
92 | * lock @wusbhc->mutex. | ||
93 | */ | ||
94 | |||
95 | #include <linux/jiffies.h> | ||
96 | #include <linux/ctype.h> | ||
97 | #include <linux/workqueue.h> | ||
98 | #include "wusbhc.h" | ||
99 | |||
100 | #undef D_LOCAL | ||
101 | #define D_LOCAL 1 | ||
102 | #include <linux/uwb/debug.h> | ||
103 | |||
104 | static void wusbhc_devconnect_acked_work(struct work_struct *work); | ||
105 | |||
106 | static void wusb_dev_free(struct wusb_dev *wusb_dev) | ||
107 | { | ||
108 | if (wusb_dev) { | ||
109 | kfree(wusb_dev->set_gtk_req); | ||
110 | usb_free_urb(wusb_dev->set_gtk_urb); | ||
111 | kfree(wusb_dev); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc) | ||
116 | { | ||
117 | struct wusb_dev *wusb_dev; | ||
118 | struct urb *urb; | ||
119 | struct usb_ctrlrequest *req; | ||
120 | |||
121 | wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL); | ||
122 | if (wusb_dev == NULL) | ||
123 | goto err; | ||
124 | |||
125 | wusb_dev->wusbhc = wusbhc; | ||
126 | |||
127 | INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work); | ||
128 | |||
129 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
130 | if (urb == NULL) | ||
131 | goto err; | ||
132 | |||
133 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); | ||
134 | if (req == NULL) | ||
135 | goto err; | ||
136 | |||
137 | req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; | ||
138 | req->bRequest = USB_REQ_SET_DESCRIPTOR; | ||
139 | req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index); | ||
140 | req->wIndex = 0; | ||
141 | req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength); | ||
142 | |||
143 | wusb_dev->set_gtk_urb = urb; | ||
144 | wusb_dev->set_gtk_req = req; | ||
145 | |||
146 | return wusb_dev; | ||
147 | err: | ||
148 | wusb_dev_free(wusb_dev); | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | |||
153 | /* | ||
154 | * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE | ||
155 | * properly so that it can be added to the MMC. | ||
156 | * | ||
157 | * We just get the @wusbhc->ca_list and fill out the first four ones or | ||
158 | * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB | ||
159 | * IE is not allocated, we alloc it. | ||
160 | * | ||
161 | * @wusbhc->mutex must be taken | ||
162 | */ | ||
163 | static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc) | ||
164 | { | ||
165 | unsigned cnt; | ||
166 | struct wusb_dev *dev_itr; | ||
167 | struct wuie_connect_ack *cack_ie; | ||
168 | |||
169 | cack_ie = &wusbhc->cack_ie; | ||
170 | cnt = 0; | ||
171 | list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) { | ||
172 | cack_ie->blk[cnt].CDID = dev_itr->cdid; | ||
173 | cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr; | ||
174 | if (++cnt >= WUIE_ELT_MAX) | ||
175 | break; | ||
176 | } | ||
177 | cack_ie->hdr.bLength = sizeof(cack_ie->hdr) | ||
178 | + cnt * sizeof(cack_ie->blk[0]); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Register a new device that wants to connect | ||
183 | * | ||
184 | * A new device wants to connect, so we add it to the Connect-Ack | ||
185 | * list. We give it an address in the unauthorized range (bit 8 set); | ||
186 | * user space will have to drive authorization further on. | ||
187 | * | ||
188 | * @dev_addr: address to use for the device (which is also the port | ||
189 | * number). | ||
190 | * | ||
191 | * @wusbhc->mutex must be taken | ||
192 | */ | ||
193 | static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc, | ||
194 | struct wusb_dn_connect *dnc, | ||
195 | const char *pr_cdid, u8 port_idx) | ||
196 | { | ||
197 | struct device *dev = wusbhc->dev; | ||
198 | struct wusb_dev *wusb_dev; | ||
199 | int new_connection = wusb_dn_connect_new_connection(dnc); | ||
200 | u8 dev_addr; | ||
201 | int result; | ||
202 | |||
203 | /* Is it registered already? */ | ||
204 | list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node) | ||
205 | if (!memcmp(&wusb_dev->cdid, &dnc->CDID, | ||
206 | sizeof(wusb_dev->cdid))) | ||
207 | return wusb_dev; | ||
208 | /* We don't have it, create an entry, register it */ | ||
209 | wusb_dev = wusb_dev_alloc(wusbhc); | ||
210 | if (wusb_dev == NULL) | ||
211 | return NULL; | ||
212 | wusb_dev_init(wusb_dev); | ||
213 | wusb_dev->cdid = dnc->CDID; | ||
214 | wusb_dev->port_idx = port_idx; | ||
215 | |||
216 | /* | ||
217 | * Devices are always available within the cluster reservation | ||
218 | * and since the hardware will take the intersection of the | ||
219 | * per-device availability and the cluster reservation, the | ||
220 | * per-device availability can simply be set to always | ||
221 | * available. | ||
222 | */ | ||
223 | bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS); | ||
224 | |||
225 | /* FIXME: handle reconnects instead of assuming connects are | ||
226 | always new. */ | ||
227 | if (1 && new_connection == 0) | ||
228 | new_connection = 1; | ||
229 | if (new_connection) { | ||
230 | dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH; | ||
231 | |||
232 | dev_info(dev, "Connecting new WUSB device to address %u, " | ||
233 | "port %u\n", dev_addr, port_idx); | ||
234 | |||
235 | result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr); | ||
236 | if (result < 0) | ||
237 | return NULL; | ||
238 | } | ||
239 | wusb_dev->entry_ts = jiffies; | ||
240 | list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list); | ||
241 | wusbhc->cack_count++; | ||
242 | wusbhc_fill_cack_ie(wusbhc); | ||
243 | return wusb_dev; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Remove a Connect-Ack context entry from the HCs view | ||
248 | * | ||
249 | * @wusbhc->mutex must be taken | ||
250 | */ | ||
251 | static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
252 | { | ||
253 | struct device *dev = wusbhc->dev; | ||
254 | d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); | ||
255 | list_del_init(&wusb_dev->cack_node); | ||
256 | wusbhc->cack_count--; | ||
257 | wusbhc_fill_cack_ie(wusbhc); | ||
258 | d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * @wusbhc->mutex must be taken */ | ||
263 | static | ||
264 | void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
265 | { | ||
266 | struct device *dev = wusbhc->dev; | ||
267 | d_fnstart(3, dev, "(wusbhc %p wusb_dev %p)\n", wusbhc, wusb_dev); | ||
268 | wusbhc_cack_rm(wusbhc, wusb_dev); | ||
269 | if (wusbhc->cack_count) | ||
270 | wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); | ||
271 | else | ||
272 | wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr); | ||
273 | d_fnend(3, dev, "(wusbhc %p wusb_dev %p) = void\n", wusbhc, wusb_dev); | ||
274 | } | ||
275 | |||
276 | static void wusbhc_devconnect_acked_work(struct work_struct *work) | ||
277 | { | ||
278 | struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev, | ||
279 | devconnect_acked_work); | ||
280 | struct wusbhc *wusbhc = wusb_dev->wusbhc; | ||
281 | |||
282 | mutex_lock(&wusbhc->mutex); | ||
283 | wusbhc_devconnect_acked(wusbhc, wusb_dev); | ||
284 | mutex_unlock(&wusbhc->mutex); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Ack a device for connection | ||
289 | * | ||
290 | * FIXME: docs | ||
291 | * | ||
292 | * @pr_cdid: Printable CDID...hex Use @dnc->cdid for the real deal. | ||
293 | * | ||
294 | * So we get the connect ack IE (may have been allocated already), | ||
295 | * find an empty connect block, an empty virtual port, create an | ||
296 | * address with it (see below), make it an unauth addr [bit 7 set] and | ||
297 | * set the MMC. | ||
298 | * | ||
299 | * Addresses: because WUSB hosts have no downstream hubs, we can do a | ||
300 | * 1:1 mapping between 'port number' and device | ||
301 | * address. This simplifies many things, as during this | ||
302 | * initial connect phase the USB stack has no knoledge of | ||
303 | * the device and hasn't assigned an address yet--we know | ||
304 | * USB's choose_address() will use the same euristics we | ||
305 | * use here, so we can assume which address will be assigned. | ||
306 | * | ||
307 | * USB stack always assigns address 1 to the root hub, so | ||
308 | * to the port number we add 2 (thus virtual port #0 is | ||
309 | * addr #2). | ||
310 | * | ||
311 | * @wusbhc shall be referenced | ||
312 | */ | ||
313 | static | ||
314 | void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, | ||
315 | const char *pr_cdid) | ||
316 | { | ||
317 | int result; | ||
318 | struct device *dev = wusbhc->dev; | ||
319 | struct wusb_dev *wusb_dev; | ||
320 | struct wusb_port *port; | ||
321 | unsigned idx, devnum; | ||
322 | |||
323 | d_fnstart(3, dev, "(%p, %p, %s)\n", wusbhc, dnc, pr_cdid); | ||
324 | mutex_lock(&wusbhc->mutex); | ||
325 | |||
326 | /* Check we are not handling it already */ | ||
327 | for (idx = 0; idx < wusbhc->ports_max; idx++) { | ||
328 | port = wusb_port_by_idx(wusbhc, idx); | ||
329 | if (port->wusb_dev | ||
330 | && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0) | ||
331 | goto error_unlock; | ||
332 | } | ||
333 | /* Look up those fake ports we have for a free one */ | ||
334 | for (idx = 0; idx < wusbhc->ports_max; idx++) { | ||
335 | port = wusb_port_by_idx(wusbhc, idx); | ||
336 | if ((port->status & USB_PORT_STAT_POWER) | ||
337 | && !(port->status & USB_PORT_STAT_CONNECTION)) | ||
338 | break; | ||
339 | } | ||
340 | if (idx >= wusbhc->ports_max) { | ||
341 | dev_err(dev, "Host controller can't connect more devices " | ||
342 | "(%u already connected); device %s rejected\n", | ||
343 | wusbhc->ports_max, pr_cdid); | ||
344 | /* NOTE: we could send a WUIE_Disconnect here, but we haven't | ||
345 | * event acked, so the device will eventually timeout the | ||
346 | * connection, right? */ | ||
347 | goto error_unlock; | ||
348 | } | ||
349 | |||
350 | devnum = idx + 2; | ||
351 | |||
352 | /* Make sure we are using no crypto on that "virtual port" */ | ||
353 | wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0); | ||
354 | |||
355 | /* Grab a filled in Connect-Ack context, fill out the | ||
356 | * Connect-Ack Wireless USB IE, set the MMC */ | ||
357 | wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx); | ||
358 | if (wusb_dev == NULL) | ||
359 | goto error_unlock; | ||
360 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); | ||
361 | if (result < 0) | ||
362 | goto error_unlock; | ||
363 | /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do | ||
364 | * three for a good measure */ | ||
365 | msleep(3); | ||
366 | port->wusb_dev = wusb_dev; | ||
367 | port->status |= USB_PORT_STAT_CONNECTION; | ||
368 | port->change |= USB_PORT_STAT_C_CONNECTION; | ||
369 | port->reset_count = 0; | ||
370 | /* Now the port status changed to connected; khubd will | ||
371 | * pick the change up and try to reset the port to bring it to | ||
372 | * the enabled state--so this process returns up to the stack | ||
373 | * and it calls back into wusbhc_rh_port_reset() who will call | ||
374 | * devconnect_auth(). | ||
375 | */ | ||
376 | error_unlock: | ||
377 | mutex_unlock(&wusbhc->mutex); | ||
378 | d_fnend(3, dev, "(%p, %p, %s) = void\n", wusbhc, dnc, pr_cdid); | ||
379 | return; | ||
380 | |||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Disconnect a Wireless USB device from its fake port | ||
385 | * | ||
386 | * Marks the port as disconnected so that khubd can pick up the change | ||
387 | * and drops our knowledge about the device. | ||
388 | * | ||
389 | * Assumes there is a device connected | ||
390 | * | ||
391 | * @port_index: zero based port number | ||
392 | * | ||
393 | * NOTE: @wusbhc->mutex is locked | ||
394 | * | ||
395 | * WARNING: From here it is not very safe to access anything hanging off | ||
396 | * wusb_dev | ||
397 | */ | ||
398 | static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, | ||
399 | struct wusb_port *port) | ||
400 | { | ||
401 | struct device *dev = wusbhc->dev; | ||
402 | struct wusb_dev *wusb_dev = port->wusb_dev; | ||
403 | |||
404 | d_fnstart(3, dev, "(wusbhc %p, port %p)\n", wusbhc, port); | ||
405 | port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | ||
406 | | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET | ||
407 | | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); | ||
408 | port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE; | ||
409 | if (wusb_dev) { | ||
410 | if (!list_empty(&wusb_dev->cack_node)) | ||
411 | list_del_init(&wusb_dev->cack_node); | ||
412 | /* For the one in cack_add() */ | ||
413 | wusb_dev_put(wusb_dev); | ||
414 | } | ||
415 | port->wusb_dev = NULL; | ||
416 | /* don't reset the reset_count to zero or wusbhc_rh_port_reset will get | ||
417 | * confused! We only reset to zero when we connect a new device. | ||
418 | */ | ||
419 | |||
420 | /* After a device disconnects, change the GTK (see [WUSB] | ||
421 | * section 6.2.11.2). */ | ||
422 | wusbhc_gtk_rekey(wusbhc); | ||
423 | |||
424 | d_fnend(3, dev, "(wusbhc %p, port %p) = void\n", wusbhc, port); | ||
425 | /* The Wireless USB part has forgotten about the device already; now | ||
426 | * khubd's timer will pick up the disconnection and remove the USB | ||
427 | * device from the system | ||
428 | */ | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Authenticate a device into the WUSB Cluster | ||
433 | * | ||
434 | * Called from the Root Hub code (rh.c:wusbhc_rh_port_reset()) when | ||
435 | * asking for a reset on a port that is not enabled (ie: first connect | ||
436 | * on the port). | ||
437 | * | ||
438 | * Performs the 4way handshake to allow the device to comunicate w/ the | ||
439 | * WUSB Cluster securely; once done, issue a request to the device for | ||
440 | * it to change to address 0. | ||
441 | * | ||
442 | * This mimics the reset step of Wired USB that once resetting a | ||
443 | * device, leaves the port in enabled state and the dev with the | ||
444 | * default address (0). | ||
445 | * | ||
446 | * WUSB1.0[7.1.2] | ||
447 | * | ||
448 | * @port_idx: port where the change happened--This is the index into | ||
449 | * the wusbhc port array, not the USB port number. | ||
450 | */ | ||
451 | int wusbhc_devconnect_auth(struct wusbhc *wusbhc, u8 port_idx) | ||
452 | { | ||
453 | struct device *dev = wusbhc->dev; | ||
454 | struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); | ||
455 | |||
456 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
457 | port->status &= ~USB_PORT_STAT_RESET; | ||
458 | port->status |= USB_PORT_STAT_ENABLE; | ||
459 | port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; | ||
460 | d_fnend(3, dev, "(%p, %u) = 0\n", wusbhc, port_idx); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * Refresh the list of keep alives to emit in the MMC | ||
466 | * | ||
467 | * Some devices don't respond to keep alives unless they've been | ||
468 | * authenticated, so skip unauthenticated devices. | ||
469 | * | ||
470 | * We only publish the first four devices that have a coming timeout | ||
471 | * condition. Then when we are done processing those, we go for the | ||
472 | * next ones. We ignore the ones that have timed out already (they'll | ||
473 | * be purged). | ||
474 | * | ||
475 | * This might cause the first devices to timeout the last devices in | ||
476 | * the port array...FIXME: come up with a better algorithm? | ||
477 | * | ||
478 | * Note we can't do much about MMC's ops errors; we hope next refresh | ||
479 | * will kind of handle it. | ||
480 | * | ||
481 | * NOTE: @wusbhc->mutex is locked | ||
482 | */ | ||
483 | static void __wusbhc_keep_alive(struct wusbhc *wusbhc) | ||
484 | { | ||
485 | struct device *dev = wusbhc->dev; | ||
486 | unsigned cnt; | ||
487 | struct wusb_dev *wusb_dev; | ||
488 | struct wusb_port *wusb_port; | ||
489 | struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie; | ||
490 | unsigned keep_alives, old_keep_alives; | ||
491 | |||
492 | old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr); | ||
493 | keep_alives = 0; | ||
494 | for (cnt = 0; | ||
495 | keep_alives <= WUIE_ELT_MAX && cnt < wusbhc->ports_max; | ||
496 | cnt++) { | ||
497 | unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout); | ||
498 | |||
499 | wusb_port = wusb_port_by_idx(wusbhc, cnt); | ||
500 | wusb_dev = wusb_port->wusb_dev; | ||
501 | |||
502 | if (wusb_dev == NULL) | ||
503 | continue; | ||
504 | if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated) | ||
505 | continue; | ||
506 | |||
507 | if (time_after(jiffies, wusb_dev->entry_ts + tt)) { | ||
508 | dev_err(dev, "KEEPALIVE: device %u timed out\n", | ||
509 | wusb_dev->addr); | ||
510 | __wusbhc_dev_disconnect(wusbhc, wusb_port); | ||
511 | } else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) { | ||
512 | /* Approaching timeout cut out, need to refresh */ | ||
513 | ie->bDeviceAddress[keep_alives++] = wusb_dev->addr; | ||
514 | } | ||
515 | } | ||
516 | if (keep_alives & 0x1) /* pad to even number ([WUSB] section 7.5.9) */ | ||
517 | ie->bDeviceAddress[keep_alives++] = 0x7f; | ||
518 | ie->hdr.bLength = sizeof(ie->hdr) + | ||
519 | keep_alives*sizeof(ie->bDeviceAddress[0]); | ||
520 | if (keep_alives > 0) | ||
521 | wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr); | ||
522 | else if (old_keep_alives != 0) | ||
523 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * Do a run through all devices checking for timeouts | ||
528 | */ | ||
529 | static void wusbhc_keep_alive_run(struct work_struct *ws) | ||
530 | { | ||
531 | struct delayed_work *dw = | ||
532 | container_of(ws, struct delayed_work, work); | ||
533 | struct wusbhc *wusbhc = | ||
534 | container_of(dw, struct wusbhc, keep_alive_timer); | ||
535 | |||
536 | d_fnstart(5, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
537 | if (wusbhc->active) { | ||
538 | mutex_lock(&wusbhc->mutex); | ||
539 | __wusbhc_keep_alive(wusbhc); | ||
540 | mutex_unlock(&wusbhc->mutex); | ||
541 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
542 | (wusbhc->trust_timeout * CONFIG_HZ)/1000/2); | ||
543 | } | ||
544 | d_fnend(5, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
545 | return; | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * Find the wusb_dev from its device address. | ||
550 | * | ||
551 | * The device can be found directly from the address (see | ||
552 | * wusb_cack_add() for where the device address is set to port_idx | ||
553 | * +2), except when the address is zero. | ||
554 | */ | ||
555 | static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr) | ||
556 | { | ||
557 | int p; | ||
558 | |||
559 | if (addr == 0xff) /* unconnected */ | ||
560 | return NULL; | ||
561 | |||
562 | if (addr > 0) { | ||
563 | int port = (addr & ~0x80) - 2; | ||
564 | if (port < 0 || port >= wusbhc->ports_max) | ||
565 | return NULL; | ||
566 | return wusb_port_by_idx(wusbhc, port)->wusb_dev; | ||
567 | } | ||
568 | |||
569 | /* Look for the device with address 0. */ | ||
570 | for (p = 0; p < wusbhc->ports_max; p++) { | ||
571 | struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev; | ||
572 | if (wusb_dev && wusb_dev->addr == addr) | ||
573 | return wusb_dev; | ||
574 | } | ||
575 | return NULL; | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * Handle a DN_Alive notification (WUSB1.0[7.6.1]) | ||
580 | * | ||
581 | * This just updates the device activity timestamp and then refreshes | ||
582 | * the keep alive IE. | ||
583 | * | ||
584 | * @wusbhc shall be referenced and unlocked | ||
585 | */ | ||
586 | static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
587 | { | ||
588 | struct device *dev = wusbhc->dev; | ||
589 | |||
590 | d_printf(2, dev, "DN ALIVE: device 0x%02x pong\n", wusb_dev->addr); | ||
591 | |||
592 | mutex_lock(&wusbhc->mutex); | ||
593 | wusb_dev->entry_ts = jiffies; | ||
594 | __wusbhc_keep_alive(wusbhc); | ||
595 | mutex_unlock(&wusbhc->mutex); | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * Handle a DN_Connect notification (WUSB1.0[7.6.1]) | ||
600 | * | ||
601 | * @wusbhc | ||
602 | * @pkt_hdr | ||
603 | * @size: Size of the buffer where the notification resides; if the | ||
604 | * notification data suggests there should be more data than | ||
605 | * available, an error will be signaled and the whole buffer | ||
606 | * consumed. | ||
607 | * | ||
608 | * @wusbhc->mutex shall be held | ||
609 | */ | ||
610 | static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, | ||
611 | struct wusb_dn_hdr *dn_hdr, | ||
612 | size_t size) | ||
613 | { | ||
614 | struct device *dev = wusbhc->dev; | ||
615 | struct wusb_dn_connect *dnc; | ||
616 | char pr_cdid[WUSB_CKHDID_STRSIZE]; | ||
617 | static const char *beacon_behaviour[] = { | ||
618 | "reserved", | ||
619 | "self-beacon", | ||
620 | "directed-beacon", | ||
621 | "no-beacon" | ||
622 | }; | ||
623 | |||
624 | d_fnstart(3, dev, "(%p, %p, %zu)\n", wusbhc, dn_hdr, size); | ||
625 | if (size < sizeof(*dnc)) { | ||
626 | dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n", | ||
627 | size, sizeof(*dnc)); | ||
628 | goto out; | ||
629 | } | ||
630 | |||
631 | dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); | ||
632 | ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); | ||
633 | dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", | ||
634 | pr_cdid, | ||
635 | wusb_dn_connect_prev_dev_addr(dnc), | ||
636 | beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)], | ||
637 | wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect"); | ||
638 | /* ACK the connect */ | ||
639 | wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid); | ||
640 | out: | ||
641 | d_fnend(3, dev, "(%p, %p, %zu) = void\n", | ||
642 | wusbhc, dn_hdr, size); | ||
643 | return; | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * Handle a DN_Disconnect notification (WUSB1.0[7.6.1]) | ||
648 | * | ||
649 | * Device is going down -- do the disconnect. | ||
650 | * | ||
651 | * @wusbhc shall be referenced and unlocked | ||
652 | */ | ||
653 | static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
654 | { | ||
655 | struct device *dev = wusbhc->dev; | ||
656 | |||
657 | dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr); | ||
658 | |||
659 | mutex_lock(&wusbhc->mutex); | ||
660 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); | ||
661 | mutex_unlock(&wusbhc->mutex); | ||
662 | } | ||
663 | |||
664 | /* | ||
665 | * Reset a WUSB device on a HWA | ||
666 | * | ||
667 | * @wusbhc | ||
668 | * @port_idx Index of the port where the device is | ||
669 | * | ||
670 | * In Wireless USB, a reset is more or less equivalent to a full | ||
671 | * disconnect; so we just do a full disconnect and send the device a | ||
672 | * Device Reset IE (WUSB1.0[7.5.11]) giving it a few millisecs (6 MMCs). | ||
673 | * | ||
674 | * @wusbhc should be refcounted and unlocked | ||
675 | */ | ||
676 | int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port_idx) | ||
677 | { | ||
678 | int result; | ||
679 | struct device *dev = wusbhc->dev; | ||
680 | struct wusb_dev *wusb_dev; | ||
681 | struct wuie_reset *ie; | ||
682 | |||
683 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
684 | mutex_lock(&wusbhc->mutex); | ||
685 | result = 0; | ||
686 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
687 | if (wusb_dev == NULL) { | ||
688 | /* reset no device? ignore */ | ||
689 | dev_dbg(dev, "RESET: no device at port %u, ignoring\n", | ||
690 | port_idx); | ||
691 | goto error_unlock; | ||
692 | } | ||
693 | result = -ENOMEM; | ||
694 | ie = kzalloc(sizeof(*ie), GFP_KERNEL); | ||
695 | if (ie == NULL) | ||
696 | goto error_unlock; | ||
697 | ie->hdr.bLength = sizeof(ie->hdr) + sizeof(ie->CDID); | ||
698 | ie->hdr.bIEIdentifier = WUIE_ID_RESET_DEVICE; | ||
699 | ie->CDID = wusb_dev->cdid; | ||
700 | result = wusbhc_mmcie_set(wusbhc, 0xff, 6, &ie->hdr); | ||
701 | if (result < 0) { | ||
702 | dev_err(dev, "RESET: cant's set MMC: %d\n", result); | ||
703 | goto error_kfree; | ||
704 | } | ||
705 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
706 | |||
707 | /* 120ms, hopefully 6 MMCs (FIXME) */ | ||
708 | msleep(120); | ||
709 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
710 | error_kfree: | ||
711 | kfree(ie); | ||
712 | error_unlock: | ||
713 | mutex_unlock(&wusbhc->mutex); | ||
714 | d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); | ||
715 | return result; | ||
716 | } | ||
717 | |||
718 | /* | ||
719 | * Handle a Device Notification coming a host | ||
720 | * | ||
721 | * The Device Notification comes from a host (HWA, DWA or WHCI) | ||
722 | * wrapped in a set of headers. Somebody else has peeled off those | ||
723 | * headers for us and we just get one Device Notifications. | ||
724 | * | ||
725 | * Invalid DNs (e.g., too short) are discarded. | ||
726 | * | ||
727 | * @wusbhc shall be referenced | ||
728 | * | ||
729 | * FIXMES: | ||
730 | * - implement priorities as in WUSB1.0[Table 7-55]? | ||
731 | */ | ||
732 | void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, | ||
733 | struct wusb_dn_hdr *dn_hdr, size_t size) | ||
734 | { | ||
735 | struct device *dev = wusbhc->dev; | ||
736 | struct wusb_dev *wusb_dev; | ||
737 | |||
738 | d_fnstart(3, dev, "(%p, %p)\n", wusbhc, dn_hdr); | ||
739 | |||
740 | if (size < sizeof(struct wusb_dn_hdr)) { | ||
741 | dev_err(dev, "DN data shorter than DN header (%d < %d)\n", | ||
742 | (int)size, (int)sizeof(struct wusb_dn_hdr)); | ||
743 | goto out; | ||
744 | } | ||
745 | |||
746 | wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); | ||
747 | if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) { | ||
748 | dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n", | ||
749 | dn_hdr->bType, srcaddr); | ||
750 | goto out; | ||
751 | } | ||
752 | |||
753 | switch (dn_hdr->bType) { | ||
754 | case WUSB_DN_CONNECT: | ||
755 | wusbhc_handle_dn_connect(wusbhc, dn_hdr, size); | ||
756 | break; | ||
757 | case WUSB_DN_ALIVE: | ||
758 | wusbhc_handle_dn_alive(wusbhc, wusb_dev); | ||
759 | break; | ||
760 | case WUSB_DN_DISCONNECT: | ||
761 | wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); | ||
762 | break; | ||
763 | case WUSB_DN_MASAVAILCHANGED: | ||
764 | case WUSB_DN_RWAKE: | ||
765 | case WUSB_DN_SLEEP: | ||
766 | /* FIXME: handle these DNs. */ | ||
767 | break; | ||
768 | case WUSB_DN_EPRDY: | ||
769 | /* The hardware handles these. */ | ||
770 | break; | ||
771 | default: | ||
772 | dev_warn(dev, "unknown DN %u (%d octets) from %u\n", | ||
773 | dn_hdr->bType, (int)size, srcaddr); | ||
774 | } | ||
775 | out: | ||
776 | d_fnend(3, dev, "(%p, %p) = void\n", wusbhc, dn_hdr); | ||
777 | return; | ||
778 | } | ||
779 | EXPORT_SYMBOL_GPL(wusbhc_handle_dn); | ||
780 | |||
781 | /* | ||
782 | * Disconnect a WUSB device from a the cluster | ||
783 | * | ||
784 | * @wusbhc | ||
785 | * @port Fake port where the device is (wusbhc index, not USB port number). | ||
786 | * | ||
787 | * In Wireless USB, a disconnect is basically telling the device he is | ||
788 | * being disconnected and forgetting about him. | ||
789 | * | ||
790 | * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100 | ||
791 | * ms and then keep going. | ||
792 | * | ||
793 | * We don't do much in case of error; we always pretend we disabled | ||
794 | * the port and disconnected the device. If physically the request | ||
795 | * didn't get there (many things can fail in the way there), the stack | ||
796 | * will reject the device's communication attempts. | ||
797 | * | ||
798 | * @wusbhc should be refcounted and locked | ||
799 | */ | ||
800 | void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx) | ||
801 | { | ||
802 | int result; | ||
803 | struct device *dev = wusbhc->dev; | ||
804 | struct wusb_dev *wusb_dev; | ||
805 | struct wuie_disconnect *ie; | ||
806 | |||
807 | d_fnstart(3, dev, "(%p, %u)\n", wusbhc, port_idx); | ||
808 | result = 0; | ||
809 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
810 | if (wusb_dev == NULL) { | ||
811 | /* reset no device? ignore */ | ||
812 | dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n", | ||
813 | port_idx); | ||
814 | goto error; | ||
815 | } | ||
816 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
817 | |||
818 | result = -ENOMEM; | ||
819 | ie = kzalloc(sizeof(*ie), GFP_KERNEL); | ||
820 | if (ie == NULL) | ||
821 | goto error; | ||
822 | ie->hdr.bLength = sizeof(*ie); | ||
823 | ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT; | ||
824 | ie->bDeviceAddress = wusb_dev->addr; | ||
825 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr); | ||
826 | if (result < 0) { | ||
827 | dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result); | ||
828 | goto error_kfree; | ||
829 | } | ||
830 | |||
831 | /* 120ms, hopefully 6 MMCs */ | ||
832 | msleep(100); | ||
833 | wusbhc_mmcie_rm(wusbhc, &ie->hdr); | ||
834 | error_kfree: | ||
835 | kfree(ie); | ||
836 | error: | ||
837 | d_fnend(3, dev, "(%p, %u) = %d\n", wusbhc, port_idx, result); | ||
838 | return; | ||
839 | } | ||
840 | |||
841 | static void wusb_cap_descr_printf(const unsigned level, struct device *dev, | ||
842 | const struct usb_wireless_cap_descriptor *wcd) | ||
843 | { | ||
844 | d_printf(level, dev, | ||
845 | "WUSB Capability Descriptor\n" | ||
846 | " bDevCapabilityType 0x%02x\n" | ||
847 | " bmAttributes 0x%02x\n" | ||
848 | " wPhyRates 0x%04x\n" | ||
849 | " bmTFITXPowerInfo 0x%02x\n" | ||
850 | " bmFFITXPowerInfo 0x%02x\n" | ||
851 | " bmBandGroup 0x%04x\n" | ||
852 | " bReserved 0x%02x\n", | ||
853 | wcd->bDevCapabilityType, | ||
854 | wcd->bmAttributes, | ||
855 | le16_to_cpu(wcd->wPHYRates), | ||
856 | wcd->bmTFITXPowerInfo, | ||
857 | wcd->bmFFITXPowerInfo, | ||
858 | wcd->bmBandGroup, | ||
859 | wcd->bReserved); | ||
860 | } | ||
861 | |||
862 | /* | ||
863 | * Walk over the BOS descriptor, verify and grok it | ||
864 | * | ||
865 | * @usb_dev: referenced | ||
866 | * @wusb_dev: referenced and unlocked | ||
867 | * | ||
868 | * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a | ||
869 | * "flexible" way to wrap all kinds of descriptors inside an standard | ||
870 | * descriptor (wonder why they didn't use normal descriptors, | ||
871 | * btw). Not like they lack code. | ||
872 | * | ||
873 | * At the end we go to look for the WUSB Device Capabilities | ||
874 | * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor | ||
875 | * that is part of the BOS descriptor set. That tells us what does the | ||
876 | * device support (dual role, beacon type, UWB PHY rates). | ||
877 | */ | ||
878 | static int wusb_dev_bos_grok(struct usb_device *usb_dev, | ||
879 | struct wusb_dev *wusb_dev, | ||
880 | struct usb_bos_descriptor *bos, size_t desc_size) | ||
881 | { | ||
882 | ssize_t result; | ||
883 | struct device *dev = &usb_dev->dev; | ||
884 | void *itr, *top; | ||
885 | |||
886 | /* Walk over BOS capabilities, verify them */ | ||
887 | itr = (void *)bos + sizeof(*bos); | ||
888 | top = itr + desc_size - sizeof(*bos); | ||
889 | while (itr < top) { | ||
890 | struct usb_dev_cap_header *cap_hdr = itr; | ||
891 | size_t cap_size; | ||
892 | u8 cap_type; | ||
893 | if (top - itr < sizeof(*cap_hdr)) { | ||
894 | dev_err(dev, "Device BUG? premature end of BOS header " | ||
895 | "data [offset 0x%02x]: only %zu bytes left\n", | ||
896 | (int)(itr - (void *)bos), top - itr); | ||
897 | result = -ENOSPC; | ||
898 | goto error_bad_cap; | ||
899 | } | ||
900 | cap_size = cap_hdr->bLength; | ||
901 | cap_type = cap_hdr->bDevCapabilityType; | ||
902 | d_printf(4, dev, "BOS Capability: 0x%02x (%zu bytes)\n", | ||
903 | cap_type, cap_size); | ||
904 | if (cap_size == 0) | ||
905 | break; | ||
906 | if (cap_size > top - itr) { | ||
907 | dev_err(dev, "Device BUG? premature end of BOS data " | ||
908 | "[offset 0x%02x cap %02x %zu bytes]: " | ||
909 | "only %zu bytes left\n", | ||
910 | (int)(itr - (void *)bos), | ||
911 | cap_type, cap_size, top - itr); | ||
912 | result = -EBADF; | ||
913 | goto error_bad_cap; | ||
914 | } | ||
915 | d_dump(3, dev, itr, cap_size); | ||
916 | switch (cap_type) { | ||
917 | case USB_CAP_TYPE_WIRELESS_USB: | ||
918 | if (cap_size != sizeof(*wusb_dev->wusb_cap_descr)) | ||
919 | dev_err(dev, "Device BUG? WUSB Capability " | ||
920 | "descriptor is %zu bytes vs %zu " | ||
921 | "needed\n", cap_size, | ||
922 | sizeof(*wusb_dev->wusb_cap_descr)); | ||
923 | else { | ||
924 | wusb_dev->wusb_cap_descr = itr; | ||
925 | wusb_cap_descr_printf(3, dev, itr); | ||
926 | } | ||
927 | break; | ||
928 | default: | ||
929 | dev_err(dev, "BUG? Unknown BOS capability 0x%02x " | ||
930 | "(%zu bytes) at offset 0x%02x\n", cap_type, | ||
931 | cap_size, (int)(itr - (void *)bos)); | ||
932 | } | ||
933 | itr += cap_size; | ||
934 | } | ||
935 | result = 0; | ||
936 | error_bad_cap: | ||
937 | return result; | ||
938 | } | ||
939 | |||
940 | /* | ||
941 | * Add information from the BOS descriptors to the device | ||
942 | * | ||
943 | * @usb_dev: referenced | ||
944 | * @wusb_dev: referenced and unlocked | ||
945 | * | ||
946 | * So what we do is we alloc a space for the BOS descriptor of 64 | ||
947 | * bytes; read the first four bytes which include the wTotalLength | ||
948 | * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the | ||
949 | * whole thing. If not we realloc to that size. | ||
950 | * | ||
951 | * Then we call the groking function, that will fill up | ||
952 | * wusb_dev->wusb_cap_descr, which is what we'll need later on. | ||
953 | */ | ||
954 | static int wusb_dev_bos_add(struct usb_device *usb_dev, | ||
955 | struct wusb_dev *wusb_dev) | ||
956 | { | ||
957 | ssize_t result; | ||
958 | struct device *dev = &usb_dev->dev; | ||
959 | struct usb_bos_descriptor *bos; | ||
960 | size_t alloc_size = 32, desc_size = 4; | ||
961 | |||
962 | bos = kmalloc(alloc_size, GFP_KERNEL); | ||
963 | if (bos == NULL) | ||
964 | return -ENOMEM; | ||
965 | result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); | ||
966 | if (result < 4) { | ||
967 | dev_err(dev, "Can't get BOS descriptor or too short: %zd\n", | ||
968 | result); | ||
969 | goto error_get_descriptor; | ||
970 | } | ||
971 | desc_size = le16_to_cpu(bos->wTotalLength); | ||
972 | if (desc_size >= alloc_size) { | ||
973 | kfree(bos); | ||
974 | alloc_size = desc_size; | ||
975 | bos = kmalloc(alloc_size, GFP_KERNEL); | ||
976 | if (bos == NULL) | ||
977 | return -ENOMEM; | ||
978 | } | ||
979 | result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); | ||
980 | if (result < 0 || result != desc_size) { | ||
981 | dev_err(dev, "Can't get BOS descriptor or too short (need " | ||
982 | "%zu bytes): %zd\n", desc_size, result); | ||
983 | goto error_get_descriptor; | ||
984 | } | ||
985 | if (result < sizeof(*bos) | ||
986 | || le16_to_cpu(bos->wTotalLength) != desc_size) { | ||
987 | dev_err(dev, "Can't get BOS descriptor or too short (need " | ||
988 | "%zu bytes): %zd\n", desc_size, result); | ||
989 | goto error_get_descriptor; | ||
990 | } | ||
991 | d_printf(2, dev, "Got BOS descriptor %zd bytes, %u capabilities\n", | ||
992 | result, bos->bNumDeviceCaps); | ||
993 | d_dump(2, dev, bos, result); | ||
994 | result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result); | ||
995 | if (result < 0) | ||
996 | goto error_bad_bos; | ||
997 | wusb_dev->bos = bos; | ||
998 | return 0; | ||
999 | |||
1000 | error_bad_bos: | ||
1001 | error_get_descriptor: | ||
1002 | kfree(bos); | ||
1003 | wusb_dev->wusb_cap_descr = NULL; | ||
1004 | return result; | ||
1005 | } | ||
1006 | |||
1007 | static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev) | ||
1008 | { | ||
1009 | kfree(wusb_dev->bos); | ||
1010 | wusb_dev->wusb_cap_descr = NULL; | ||
1011 | }; | ||
1012 | |||
1013 | static struct usb_wireless_cap_descriptor wusb_cap_descr_default = { | ||
1014 | .bLength = sizeof(wusb_cap_descr_default), | ||
1015 | .bDescriptorType = USB_DT_DEVICE_CAPABILITY, | ||
1016 | .bDevCapabilityType = USB_CAP_TYPE_WIRELESS_USB, | ||
1017 | |||
1018 | .bmAttributes = USB_WIRELESS_BEACON_NONE, | ||
1019 | .wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53), | ||
1020 | .bmTFITXPowerInfo = 0, | ||
1021 | .bmFFITXPowerInfo = 0, | ||
1022 | .bmBandGroup = cpu_to_le16(0x0001), /* WUSB1.0[7.4.1] bottom */ | ||
1023 | .bReserved = 0 | ||
1024 | }; | ||
1025 | |||
1026 | /* | ||
1027 | * USB stack's device addition Notifier Callback | ||
1028 | * | ||
1029 | * Called from drivers/usb/core/hub.c when a new device is added; we | ||
1030 | * use this hook to perform certain WUSB specific setup work on the | ||
1031 | * new device. As well, it is the first time we can connect the | ||
1032 | * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a | ||
1033 | * reference that we'll drop. | ||
1034 | * | ||
1035 | * First we need to determine if the device is a WUSB device (else we | ||
1036 | * ignore it). For that we use the speed setting (USB_SPEED_VARIABLE) | ||
1037 | * [FIXME: maybe we'd need something more definitive]. If so, we track | ||
1038 | * it's usb_busd and from there, the WUSB HC. | ||
1039 | * | ||
1040 | * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we | ||
1041 | * get the wusbhc for the device. | ||
1042 | * | ||
1043 | * We have a reference on @usb_dev (as we are called at the end of its | ||
1044 | * enumeration). | ||
1045 | * | ||
1046 | * NOTE: @usb_dev locked | ||
1047 | */ | ||
1048 | static void wusb_dev_add_ncb(struct usb_device *usb_dev) | ||
1049 | { | ||
1050 | int result = 0; | ||
1051 | struct wusb_dev *wusb_dev; | ||
1052 | struct wusbhc *wusbhc; | ||
1053 | struct device *dev = &usb_dev->dev; | ||
1054 | u8 port_idx; | ||
1055 | |||
1056 | if (usb_dev->wusb == 0 || usb_dev->devnum == 1) | ||
1057 | return; /* skip non wusb and wusb RHs */ | ||
1058 | |||
1059 | d_fnstart(3, dev, "(usb_dev %p)\n", usb_dev); | ||
1060 | |||
1061 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
1062 | if (wusbhc == NULL) | ||
1063 | goto error_nodev; | ||
1064 | mutex_lock(&wusbhc->mutex); | ||
1065 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); | ||
1066 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
1067 | mutex_unlock(&wusbhc->mutex); | ||
1068 | if (wusb_dev == NULL) | ||
1069 | goto error_nodev; | ||
1070 | wusb_dev->usb_dev = usb_get_dev(usb_dev); | ||
1071 | usb_dev->wusb_dev = wusb_dev_get(wusb_dev); | ||
1072 | result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev); | ||
1073 | if (result < 0) { | ||
1074 | dev_err(dev, "Cannot enable security: %d\n", result); | ||
1075 | goto error_sec_add; | ||
1076 | } | ||
1077 | /* Now query the device for it's BOS and attach it to wusb_dev */ | ||
1078 | result = wusb_dev_bos_add(usb_dev, wusb_dev); | ||
1079 | if (result < 0) { | ||
1080 | dev_err(dev, "Cannot get BOS descriptors: %d\n", result); | ||
1081 | goto error_bos_add; | ||
1082 | } | ||
1083 | result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev); | ||
1084 | if (result < 0) | ||
1085 | goto error_add_sysfs; | ||
1086 | out: | ||
1087 | wusb_dev_put(wusb_dev); | ||
1088 | wusbhc_put(wusbhc); | ||
1089 | error_nodev: | ||
1090 | d_fnend(3, dev, "(usb_dev %p) = void\n", usb_dev); | ||
1091 | return; | ||
1092 | |||
1093 | wusb_dev_sysfs_rm(wusb_dev); | ||
1094 | error_add_sysfs: | ||
1095 | wusb_dev_bos_rm(wusb_dev); | ||
1096 | error_bos_add: | ||
1097 | wusb_dev_sec_rm(wusb_dev); | ||
1098 | error_sec_add: | ||
1099 | mutex_lock(&wusbhc->mutex); | ||
1100 | __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); | ||
1101 | mutex_unlock(&wusbhc->mutex); | ||
1102 | goto out; | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * Undo all the steps done at connection by the notifier callback | ||
1107 | * | ||
1108 | * NOTE: @usb_dev locked | ||
1109 | */ | ||
1110 | static void wusb_dev_rm_ncb(struct usb_device *usb_dev) | ||
1111 | { | ||
1112 | struct wusb_dev *wusb_dev = usb_dev->wusb_dev; | ||
1113 | |||
1114 | if (usb_dev->wusb == 0 || usb_dev->devnum == 1) | ||
1115 | return; /* skip non wusb and wusb RHs */ | ||
1116 | |||
1117 | wusb_dev_sysfs_rm(wusb_dev); | ||
1118 | wusb_dev_bos_rm(wusb_dev); | ||
1119 | wusb_dev_sec_rm(wusb_dev); | ||
1120 | wusb_dev->usb_dev = NULL; | ||
1121 | usb_dev->wusb_dev = NULL; | ||
1122 | wusb_dev_put(wusb_dev); | ||
1123 | usb_put_dev(usb_dev); | ||
1124 | } | ||
1125 | |||
1126 | /* | ||
1127 | * Handle notifications from the USB stack (notifier call back) | ||
1128 | * | ||
1129 | * This is called when the USB stack does a | ||
1130 | * usb_{bus,device}_{add,remove}() so we can do WUSB specific | ||
1131 | * handling. It is called with [for the case of | ||
1132 | * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked. | ||
1133 | */ | ||
1134 | int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
1135 | void *priv) | ||
1136 | { | ||
1137 | int result = NOTIFY_OK; | ||
1138 | |||
1139 | switch (val) { | ||
1140 | case USB_DEVICE_ADD: | ||
1141 | wusb_dev_add_ncb(priv); | ||
1142 | break; | ||
1143 | case USB_DEVICE_REMOVE: | ||
1144 | wusb_dev_rm_ncb(priv); | ||
1145 | break; | ||
1146 | case USB_BUS_ADD: | ||
1147 | /* ignore (for now) */ | ||
1148 | case USB_BUS_REMOVE: | ||
1149 | break; | ||
1150 | default: | ||
1151 | WARN_ON(1); | ||
1152 | result = NOTIFY_BAD; | ||
1153 | }; | ||
1154 | return result; | ||
1155 | } | ||
1156 | |||
1157 | /* | ||
1158 | * Return a referenced wusb_dev given a @wusbhc and @usb_dev | ||
1159 | */ | ||
1160 | struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc, | ||
1161 | struct usb_device *usb_dev) | ||
1162 | { | ||
1163 | struct wusb_dev *wusb_dev; | ||
1164 | u8 port_idx; | ||
1165 | |||
1166 | port_idx = wusb_port_no_to_idx(usb_dev->portnum); | ||
1167 | BUG_ON(port_idx > wusbhc->ports_max); | ||
1168 | wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; | ||
1169 | if (wusb_dev != NULL) /* ops, device is gone */ | ||
1170 | wusb_dev_get(wusb_dev); | ||
1171 | return wusb_dev; | ||
1172 | } | ||
1173 | EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev); | ||
1174 | |||
1175 | void wusb_dev_destroy(struct kref *_wusb_dev) | ||
1176 | { | ||
1177 | struct wusb_dev *wusb_dev | ||
1178 | = container_of(_wusb_dev, struct wusb_dev, refcnt); | ||
1179 | list_del_init(&wusb_dev->cack_node); | ||
1180 | wusb_dev_free(wusb_dev); | ||
1181 | d_fnend(1, NULL, "%s (wusb_dev %p) = void\n", __func__, wusb_dev); | ||
1182 | } | ||
1183 | EXPORT_SYMBOL_GPL(wusb_dev_destroy); | ||
1184 | |||
1185 | /* | ||
1186 | * Create all the device connect handling infrastructure | ||
1187 | * | ||
1188 | * This is basically the device info array, Connect Acknowledgement | ||
1189 | * (cack) lists, keep-alive timers (and delayed work thread). | ||
1190 | */ | ||
1191 | int wusbhc_devconnect_create(struct wusbhc *wusbhc) | ||
1192 | { | ||
1193 | d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
1194 | |||
1195 | wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE; | ||
1196 | wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr); | ||
1197 | INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run); | ||
1198 | |||
1199 | wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK; | ||
1200 | wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr); | ||
1201 | INIT_LIST_HEAD(&wusbhc->cack_list); | ||
1202 | |||
1203 | d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | /* | ||
1208 | * Release all resources taken by the devconnect stuff | ||
1209 | */ | ||
1210 | void wusbhc_devconnect_destroy(struct wusbhc *wusbhc) | ||
1211 | { | ||
1212 | d_fnstart(3, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
1213 | d_fnend(3, wusbhc->dev, "(wusbhc %p) = void\n", wusbhc); | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * wusbhc_devconnect_start - start accepting device connections | ||
1218 | * @wusbhc: the WUSB HC | ||
1219 | * | ||
1220 | * Sets the Host Info IE to accept all new connections. | ||
1221 | * | ||
1222 | * FIXME: This also enables the keep alives but this is not necessary | ||
1223 | * until there are connected and authenticated devices. | ||
1224 | */ | ||
1225 | int wusbhc_devconnect_start(struct wusbhc *wusbhc, | ||
1226 | const struct wusb_ckhdid *chid) | ||
1227 | { | ||
1228 | struct device *dev = wusbhc->dev; | ||
1229 | struct wuie_host_info *hi; | ||
1230 | int result; | ||
1231 | |||
1232 | hi = kzalloc(sizeof(*hi), GFP_KERNEL); | ||
1233 | if (hi == NULL) | ||
1234 | return -ENOMEM; | ||
1235 | |||
1236 | hi->hdr.bLength = sizeof(*hi); | ||
1237 | hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO; | ||
1238 | hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL); | ||
1239 | hi->CHID = *chid; | ||
1240 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr); | ||
1241 | if (result < 0) { | ||
1242 | dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result); | ||
1243 | goto error_mmcie_set; | ||
1244 | } | ||
1245 | wusbhc->wuie_host_info = hi; | ||
1246 | |||
1247 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
1248 | (wusbhc->trust_timeout*CONFIG_HZ)/1000/2); | ||
1249 | |||
1250 | return 0; | ||
1251 | |||
1252 | error_mmcie_set: | ||
1253 | kfree(hi); | ||
1254 | return result; | ||
1255 | } | ||
1256 | |||
1257 | /* | ||
1258 | * wusbhc_devconnect_stop - stop managing connected devices | ||
1259 | * @wusbhc: the WUSB HC | ||
1260 | * | ||
1261 | * Removes the Host Info IE and stops the keep alives. | ||
1262 | * | ||
1263 | * FIXME: should this disconnect all devices? | ||
1264 | */ | ||
1265 | void wusbhc_devconnect_stop(struct wusbhc *wusbhc) | ||
1266 | { | ||
1267 | cancel_delayed_work_sync(&wusbhc->keep_alive_timer); | ||
1268 | WARN_ON(!list_empty(&wusbhc->cack_list)); | ||
1269 | |||
1270 | wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr); | ||
1271 | kfree(wusbhc->wuie_host_info); | ||
1272 | wusbhc->wuie_host_info = NULL; | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1276 | * wusb_set_dev_addr - set the WUSB device address used by the host | ||
1277 | * @wusbhc: the WUSB HC the device is connect to | ||
1278 | * @wusb_dev: the WUSB device | ||
1279 | * @addr: new device address | ||
1280 | */ | ||
1281 | int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr) | ||
1282 | { | ||
1283 | int result; | ||
1284 | |||
1285 | wusb_dev->addr = addr; | ||
1286 | result = wusbhc->dev_info_set(wusbhc, wusb_dev); | ||
1287 | if (result < 0) | ||
1288 | dev_err(wusbhc->dev, "device %d: failed to set device " | ||
1289 | "address\n", wusb_dev->port_idx); | ||
1290 | else | ||
1291 | dev_info(wusbhc->dev, "device %d: %s addr %u\n", | ||
1292 | wusb_dev->port_idx, | ||
1293 | (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth", | ||
1294 | wusb_dev->addr); | ||
1295 | |||
1296 | return result; | ||
1297 | } | ||
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c new file mode 100644 index 000000000000..cfa77a01cebd --- /dev/null +++ b/drivers/usb/wusbcore/mmc.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * MMC (Microscheduled Management Command) handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * WUIEs and MMC IEs...well, they are almost the same at the end. MMC | ||
24 | * IEs are Wireless USB IEs that go into the MMC period...[what is | ||
25 | * that? look in Design-overview.txt]. | ||
26 | * | ||
27 | * | ||
28 | * This is a simple subsystem to keep track of which IEs are being | ||
29 | * sent by the host in the MMC period. | ||
30 | * | ||
31 | * For each WUIE we ask to send, we keep it in an array, so we can | ||
32 | * request its removal later, or replace the content. They are tracked | ||
33 | * by pointer, so be sure to use the same pointer if you want to | ||
34 | * remove it or update the contents. | ||
35 | * | ||
36 | * FIXME: | ||
37 | * - add timers that autoremove intervalled IEs? | ||
38 | */ | ||
39 | #include <linux/usb/wusb.h> | ||
40 | #include "wusbhc.h" | ||
41 | |||
42 | /* Initialize the MMCIEs handling mechanism */ | ||
43 | int wusbhc_mmcie_create(struct wusbhc *wusbhc) | ||
44 | { | ||
45 | u8 mmcies = wusbhc->mmcies_max; | ||
46 | wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL); | ||
47 | if (wusbhc->mmcie == NULL) | ||
48 | return -ENOMEM; | ||
49 | mutex_init(&wusbhc->mmcie_mutex); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* Release resources used by the MMCIEs handling mechanism */ | ||
54 | void wusbhc_mmcie_destroy(struct wusbhc *wusbhc) | ||
55 | { | ||
56 | kfree(wusbhc->mmcie); | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Add or replace an MMC Wireless USB IE. | ||
61 | * | ||
62 | * @interval: See WUSB1.0[8.5.3.1] | ||
63 | * @repeat_cnt: See WUSB1.0[8.5.3.1] | ||
64 | * @handle: See WUSB1.0[8.5.3.1] | ||
65 | * @wuie: Pointer to the header of the WUSB IE data to add. | ||
66 | * MUST BE allocated in a kmalloc buffer (no stack or | ||
67 | * vmalloc). | ||
68 | * THE CALLER ALWAYS OWNS THE POINTER (we don't free it | ||
69 | * on remove, we just forget about it). | ||
70 | * @returns: 0 if ok, < 0 errno code on error. | ||
71 | * | ||
72 | * Goes over the *whole* @wusbhc->mmcie array looking for (a) the | ||
73 | * first free spot and (b) if @wuie is already in the array (aka: | ||
74 | * transmitted in the MMCs) the spot were it is. | ||
75 | * | ||
76 | * If present, we "overwrite it" (update). | ||
77 | * | ||
78 | * | ||
79 | * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38. | ||
80 | * The host uses the handle as the 'sort' index. We | ||
81 | * allocate the last one always for the WUIE_ID_HOST_INFO, and | ||
82 | * the rest, first come first serve in inverse order. | ||
83 | * | ||
84 | * Host software must make sure that it adds the other IEs in | ||
85 | * the right order... the host hardware is responsible for | ||
86 | * placing the WCTA IEs in the right place with the other IEs | ||
87 | * set by host software. | ||
88 | * | ||
89 | * NOTE: we can access wusbhc->wa_descr without locking because it is | ||
90 | * read only. | ||
91 | */ | ||
92 | int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
93 | struct wuie_hdr *wuie) | ||
94 | { | ||
95 | int result = -ENOBUFS; | ||
96 | unsigned handle, itr; | ||
97 | |||
98 | /* Search a handle, taking into account the ordering */ | ||
99 | mutex_lock(&wusbhc->mmcie_mutex); | ||
100 | switch (wuie->bIEIdentifier) { | ||
101 | case WUIE_ID_HOST_INFO: | ||
102 | /* Always last */ | ||
103 | handle = wusbhc->mmcies_max - 1; | ||
104 | break; | ||
105 | case WUIE_ID_ISOCH_DISCARD: | ||
106 | dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x " | ||
107 | "unimplemented\n", wuie->bIEIdentifier); | ||
108 | result = -ENOSYS; | ||
109 | goto error_unlock; | ||
110 | default: | ||
111 | /* search for it or find the last empty slot */ | ||
112 | handle = ~0; | ||
113 | for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) { | ||
114 | if (wusbhc->mmcie[itr] == wuie) { | ||
115 | handle = itr; | ||
116 | break; | ||
117 | } | ||
118 | if (wusbhc->mmcie[itr] == NULL) | ||
119 | handle = itr; | ||
120 | } | ||
121 | if (handle == ~0) | ||
122 | goto error_unlock; | ||
123 | } | ||
124 | result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle, | ||
125 | wuie); | ||
126 | if (result >= 0) | ||
127 | wusbhc->mmcie[handle] = wuie; | ||
128 | error_unlock: | ||
129 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
130 | return result; | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(wusbhc_mmcie_set); | ||
133 | |||
134 | /* | ||
135 | * Remove an MMC IE previously added with wusbhc_mmcie_set() | ||
136 | * | ||
137 | * @wuie Pointer used to add the WUIE | ||
138 | */ | ||
139 | void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie) | ||
140 | { | ||
141 | int result; | ||
142 | unsigned handle, itr; | ||
143 | |||
144 | mutex_lock(&wusbhc->mmcie_mutex); | ||
145 | for (itr = 0; itr < wusbhc->mmcies_max; itr++) { | ||
146 | if (wusbhc->mmcie[itr] == wuie) { | ||
147 | handle = itr; | ||
148 | goto found; | ||
149 | } | ||
150 | } | ||
151 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
152 | return; | ||
153 | |||
154 | found: | ||
155 | result = (wusbhc->mmcie_rm)(wusbhc, handle); | ||
156 | if (result == 0) | ||
157 | wusbhc->mmcie[itr] = NULL; | ||
158 | mutex_unlock(&wusbhc->mmcie_mutex); | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm); | ||
161 | |||
162 | /* | ||
163 | * wusbhc_start - start transmitting MMCs and accepting connections | ||
164 | * @wusbhc: the HC to start | ||
165 | * @chid: the CHID to use for this host | ||
166 | * | ||
167 | * Establishes a cluster reservation, enables device connections, and | ||
168 | * starts MMCs with appropriate DNTS parameters. | ||
169 | */ | ||
170 | int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) | ||
171 | { | ||
172 | int result; | ||
173 | struct device *dev = wusbhc->dev; | ||
174 | |||
175 | WARN_ON(wusbhc->wuie_host_info != NULL); | ||
176 | |||
177 | result = wusbhc_rsv_establish(wusbhc); | ||
178 | if (result < 0) { | ||
179 | dev_err(dev, "cannot establish cluster reservation: %d\n", | ||
180 | result); | ||
181 | goto error_rsv_establish; | ||
182 | } | ||
183 | |||
184 | result = wusbhc_devconnect_start(wusbhc, chid); | ||
185 | if (result < 0) { | ||
186 | dev_err(dev, "error enabling device connections: %d\n", result); | ||
187 | goto error_devconnect_start; | ||
188 | } | ||
189 | |||
190 | result = wusbhc_sec_start(wusbhc); | ||
191 | if (result < 0) { | ||
192 | dev_err(dev, "error starting security in the HC: %d\n", result); | ||
193 | goto error_sec_start; | ||
194 | } | ||
195 | /* FIXME: the choice of the DNTS parameters is somewhat | ||
196 | * arbitrary */ | ||
197 | result = wusbhc->set_num_dnts(wusbhc, 0, 15); | ||
198 | if (result < 0) { | ||
199 | dev_err(dev, "Cannot set DNTS parameters: %d\n", result); | ||
200 | goto error_set_num_dnts; | ||
201 | } | ||
202 | result = wusbhc->start(wusbhc); | ||
203 | if (result < 0) { | ||
204 | dev_err(dev, "error starting wusbch: %d\n", result); | ||
205 | goto error_wusbhc_start; | ||
206 | } | ||
207 | wusbhc->active = 1; | ||
208 | return 0; | ||
209 | |||
210 | error_wusbhc_start: | ||
211 | wusbhc_sec_stop(wusbhc); | ||
212 | error_set_num_dnts: | ||
213 | error_sec_start: | ||
214 | wusbhc_devconnect_stop(wusbhc); | ||
215 | error_devconnect_start: | ||
216 | wusbhc_rsv_terminate(wusbhc); | ||
217 | error_rsv_establish: | ||
218 | return result; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Disconnect all from the WUSB Channel | ||
223 | * | ||
224 | * Send a Host Disconnect IE in the MMC, wait, don't send it any more | ||
225 | */ | ||
226 | static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc) | ||
227 | { | ||
228 | int result = -ENOMEM; | ||
229 | struct wuie_host_disconnect *host_disconnect_ie; | ||
230 | might_sleep(); | ||
231 | host_disconnect_ie = kmalloc(sizeof(*host_disconnect_ie), GFP_KERNEL); | ||
232 | if (host_disconnect_ie == NULL) | ||
233 | goto error_alloc; | ||
234 | host_disconnect_ie->hdr.bLength = sizeof(*host_disconnect_ie); | ||
235 | host_disconnect_ie->hdr.bIEIdentifier = WUIE_ID_HOST_DISCONNECT; | ||
236 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &host_disconnect_ie->hdr); | ||
237 | if (result < 0) | ||
238 | goto error_mmcie_set; | ||
239 | |||
240 | /* WUSB1.0[8.5.3.1 & 7.5.2] */ | ||
241 | msleep(100); | ||
242 | wusbhc_mmcie_rm(wusbhc, &host_disconnect_ie->hdr); | ||
243 | error_mmcie_set: | ||
244 | kfree(host_disconnect_ie); | ||
245 | error_alloc: | ||
246 | return result; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * wusbhc_stop - stop transmitting MMCs | ||
251 | * @wusbhc: the HC to stop | ||
252 | * | ||
253 | * Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs). | ||
254 | * | ||
255 | * If we can't allocate a Host Stop IE, screw it, we don't notify the | ||
256 | * devices we are disconnecting... | ||
257 | */ | ||
258 | void wusbhc_stop(struct wusbhc *wusbhc) | ||
259 | { | ||
260 | if (wusbhc->active) { | ||
261 | wusbhc->active = 0; | ||
262 | wusbhc->stop(wusbhc); | ||
263 | wusbhc_sec_stop(wusbhc); | ||
264 | __wusbhc_host_disconnect_ie(wusbhc); | ||
265 | wusbhc_devconnect_stop(wusbhc); | ||
266 | wusbhc_rsv_terminate(wusbhc); | ||
267 | } | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(wusbhc_stop); | ||
270 | |||
271 | /* | ||
272 | * Change the CHID in a WUSB Channel | ||
273 | * | ||
274 | * If it is just a new CHID, send a Host Disconnect IE and then change | ||
275 | * the CHID IE. | ||
276 | */ | ||
277 | static int __wusbhc_chid_change(struct wusbhc *wusbhc, | ||
278 | const struct wusb_ckhdid *chid) | ||
279 | { | ||
280 | int result = -ENOSYS; | ||
281 | struct device *dev = wusbhc->dev; | ||
282 | dev_err(dev, "%s() not implemented yet\n", __func__); | ||
283 | return result; | ||
284 | |||
285 | BUG_ON(wusbhc->wuie_host_info == NULL); | ||
286 | __wusbhc_host_disconnect_ie(wusbhc); | ||
287 | wusbhc->wuie_host_info->CHID = *chid; | ||
288 | result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->wuie_host_info->hdr); | ||
289 | if (result < 0) | ||
290 | dev_err(dev, "Can't update Host Info WUSB IE: %d\n", result); | ||
291 | return result; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Set/reset/update a new CHID | ||
296 | * | ||
297 | * Depending on the previous state of the MMCs, start, stop or change | ||
298 | * the sent MMC. This effectively switches the host controller on and | ||
299 | * off (radio wise). | ||
300 | */ | ||
301 | int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) | ||
302 | { | ||
303 | int result = 0; | ||
304 | |||
305 | if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0) | ||
306 | chid = NULL; | ||
307 | |||
308 | mutex_lock(&wusbhc->mutex); | ||
309 | if (wusbhc->active) { | ||
310 | if (chid) | ||
311 | result = __wusbhc_chid_change(wusbhc, chid); | ||
312 | else | ||
313 | wusbhc_stop(wusbhc); | ||
314 | } else { | ||
315 | if (chid) | ||
316 | wusbhc_start(wusbhc, chid); | ||
317 | } | ||
318 | mutex_unlock(&wusbhc->mutex); | ||
319 | return result; | ||
320 | } | ||
321 | EXPORT_SYMBOL_GPL(wusbhc_chid_set); | ||
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c new file mode 100644 index 000000000000..7cc51e9905cf --- /dev/null +++ b/drivers/usb/wusbcore/pal.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * UWB Protocol Adaptation Layer (PAL) glue. | ||
4 | * | ||
5 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include "wusbhc.h" | ||
20 | |||
21 | /** | ||
22 | * wusbhc_pal_register - register the WUSB HC as a UWB PAL | ||
23 | * @wusbhc: the WUSB HC | ||
24 | */ | ||
25 | int wusbhc_pal_register(struct wusbhc *wusbhc) | ||
26 | { | ||
27 | uwb_pal_init(&wusbhc->pal); | ||
28 | |||
29 | wusbhc->pal.name = "wusbhc"; | ||
30 | wusbhc->pal.device = wusbhc->usb_hcd.self.controller; | ||
31 | |||
32 | return uwb_pal_register(wusbhc->uwb_rc, &wusbhc->pal); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL | ||
37 | * @wusbhc: the WUSB HC | ||
38 | */ | ||
39 | void wusbhc_pal_unregister(struct wusbhc *wusbhc) | ||
40 | { | ||
41 | uwb_pal_unregister(wusbhc->uwb_rc, &wusbhc->pal); | ||
42 | } | ||
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c new file mode 100644 index 000000000000..fc63e77ded2d --- /dev/null +++ b/drivers/usb/wusbcore/reservation.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * WUSB cluster reservation management | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/uwb.h> | ||
20 | |||
21 | #include "wusbhc.h" | ||
22 | |||
23 | /* | ||
24 | * WUSB cluster reservations are multicast reservations with the | ||
25 | * broadcast cluster ID (BCID) as the target DevAddr. | ||
26 | * | ||
27 | * FIXME: consider adjusting the reservation depending on what devices | ||
28 | * are attached. | ||
29 | */ | ||
30 | |||
31 | static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream, | ||
32 | const struct uwb_mas_bm *mas) | ||
33 | { | ||
34 | if (mas == NULL) | ||
35 | mas = &uwb_mas_bm_zero; | ||
36 | return wusbhc->bwa_set(wusbhc, stream, mas); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback | ||
41 | * @rsv: the reservation | ||
42 | * | ||
43 | * Either set or clear the HC's view of the reservation. | ||
44 | * | ||
45 | * FIXME: when a reservation is denied the HC should be stopped. | ||
46 | */ | ||
47 | static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) | ||
48 | { | ||
49 | struct wusbhc *wusbhc = rsv->pal_priv; | ||
50 | struct device *dev = wusbhc->dev; | ||
51 | char buf[72]; | ||
52 | |||
53 | switch (rsv->state) { | ||
54 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
55 | bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS); | ||
56 | dev_dbg(dev, "established reservation: %s\n", buf); | ||
57 | wusbhc_bwa_set(wusbhc, rsv->stream, &rsv->mas); | ||
58 | break; | ||
59 | case UWB_RSV_STATE_NONE: | ||
60 | dev_dbg(dev, "removed reservation\n"); | ||
61 | wusbhc_bwa_set(wusbhc, 0, NULL); | ||
62 | wusbhc->rsv = NULL; | ||
63 | break; | ||
64 | default: | ||
65 | dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state); | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | |||
71 | /** | ||
72 | * wusbhc_rsv_establish - establish a reservation for the cluster | ||
73 | * @wusbhc: the WUSB HC requesting a bandwith reservation | ||
74 | */ | ||
75 | int wusbhc_rsv_establish(struct wusbhc *wusbhc) | ||
76 | { | ||
77 | struct uwb_rc *rc = wusbhc->uwb_rc; | ||
78 | struct uwb_rsv *rsv; | ||
79 | struct uwb_dev_addr bcid; | ||
80 | int ret; | ||
81 | |||
82 | rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc); | ||
83 | if (rsv == NULL) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | bcid.data[0] = wusbhc->cluster_id; | ||
87 | bcid.data[1] = 0; | ||
88 | |||
89 | rsv->owner = &rc->uwb_dev; | ||
90 | rsv->target.type = UWB_RSV_TARGET_DEVADDR; | ||
91 | rsv->target.devaddr = bcid; | ||
92 | rsv->type = UWB_DRP_TYPE_PRIVATE; | ||
93 | rsv->max_mas = 256; | ||
94 | rsv->min_mas = 16; /* one MAS per zone? */ | ||
95 | rsv->sparsity = 16; /* at least one MAS in each zone? */ | ||
96 | rsv->is_multicast = true; | ||
97 | |||
98 | ret = uwb_rsv_establish(rsv); | ||
99 | if (ret == 0) | ||
100 | wusbhc->rsv = rsv; | ||
101 | else | ||
102 | uwb_rsv_destroy(rsv); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | |||
107 | /** | ||
108 | * wusbhc_rsv_terminate - terminate any cluster reservation | ||
109 | * @wusbhc: the WUSB host whose reservation is to be terminated | ||
110 | */ | ||
111 | void wusbhc_rsv_terminate(struct wusbhc *wusbhc) | ||
112 | { | ||
113 | if (wusbhc->rsv) | ||
114 | uwb_rsv_terminate(wusbhc->rsv); | ||
115 | } | ||
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c new file mode 100644 index 000000000000..267a64325106 --- /dev/null +++ b/drivers/usb/wusbcore/rh.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Root Hub operations | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * We fake a root hub that has fake ports (as many as simultaneous | ||
25 | * devices the Wireless USB Host Controller can deal with). For each | ||
26 | * port we keep an state in @wusbhc->port[index] identical to the one | ||
27 | * specified in the USB2.0[ch11] spec and some extra device | ||
28 | * information that complements the one in 'struct usb_device' (as | ||
29 | * this lacs a hcpriv pointer). | ||
30 | * | ||
31 | * Note this is common to WHCI and HWA host controllers. | ||
32 | * | ||
33 | * Through here we enable most of the state changes that the USB stack | ||
34 | * will use to connect or disconnect devices. We need to do some | ||
35 | * forced adaptation of Wireless USB device states vs. wired: | ||
36 | * | ||
37 | * USB: WUSB: | ||
38 | * | ||
39 | * Port Powered-off port slot n/a | ||
40 | * Powered-on port slot available | ||
41 | * Disconnected port slot available | ||
42 | * Connected port slot assigned device | ||
43 | * device sent DN_Connect | ||
44 | * device was authenticated | ||
45 | * Enabled device is authenticated, transitioned | ||
46 | * from unauth -> auth -> default address | ||
47 | * -> enabled | ||
48 | * Reset disconnect | ||
49 | * Disable disconnect | ||
50 | * | ||
51 | * This maps the standard USB port states with the WUSB device states | ||
52 | * so we can fake ports without having to modify the USB stack. | ||
53 | * | ||
54 | * FIXME: this process will change in the future | ||
55 | * | ||
56 | * | ||
57 | * ENTRY POINTS | ||
58 | * | ||
59 | * Our entry points into here are, as in hcd.c, the USB stack root hub | ||
60 | * ops defined in the usb_hcd struct: | ||
61 | * | ||
62 | * wusbhc_rh_status_data() Provide hub and port status data bitmap | ||
63 | * | ||
64 | * wusbhc_rh_control() Execution of all the major requests | ||
65 | * you can do to a hub (Set|Clear | ||
66 | * features, get descriptors, status, etc). | ||
67 | * | ||
68 | * wusbhc_rh_[suspend|resume]() That | ||
69 | * | ||
70 | * wusbhc_rh_start_port_reset() ??? unimplemented | ||
71 | */ | ||
72 | #include "wusbhc.h" | ||
73 | |||
74 | #define D_LOCAL 0 | ||
75 | #include <linux/uwb/debug.h> | ||
76 | |||
77 | /* | ||
78 | * Reset a fake port | ||
79 | * | ||
80 | * This can be called to reset a port from any other state or to reset | ||
81 | * it when connecting. In Wireless USB they are different; when doing | ||
82 | * a new connect that involves going over the authentication. When | ||
83 | * just reseting, its a different story. | ||
84 | * | ||
85 | * The Linux USB stack resets a port twice before it considers it | ||
86 | * enabled, so we have to detect and ignore that. | ||
87 | * | ||
88 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
89 | * | ||
90 | * Supposedly we are the only thread accesing @wusbhc->port; in any | ||
91 | * case, maybe we should move the mutex locking from | ||
92 | * wusbhc_devconnect_auth() to here. | ||
93 | * | ||
94 | * @port_idx refers to the wusbhc's port index, not the USB port number | ||
95 | */ | ||
96 | static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) | ||
97 | { | ||
98 | int result = 0; | ||
99 | struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); | ||
100 | |||
101 | d_fnstart(3, wusbhc->dev, "(wusbhc %p port_idx %u)\n", | ||
102 | wusbhc, port_idx); | ||
103 | if (port->reset_count == 0) { | ||
104 | wusbhc_devconnect_auth(wusbhc, port_idx); | ||
105 | port->reset_count++; | ||
106 | } else if (port->reset_count == 1) | ||
107 | /* see header */ | ||
108 | d_printf(2, wusbhc->dev, "Ignoring second reset on port_idx " | ||
109 | "%u\n", port_idx); | ||
110 | else | ||
111 | result = wusbhc_dev_reset(wusbhc, port_idx); | ||
112 | d_fnend(3, wusbhc->dev, "(wusbhc %p port_idx %u) = %d\n", | ||
113 | wusbhc, port_idx, result); | ||
114 | return result; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * Return the hub change status bitmap | ||
119 | * | ||
120 | * The bits in the change status bitmap are cleared when a | ||
121 | * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4]. | ||
122 | * | ||
123 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
124 | * | ||
125 | * WARNING!! This gets called from atomic context; we cannot get the | ||
126 | * mutex--the only race condition we can find is some bit | ||
127 | * changing just after we copy it, which shouldn't be too | ||
128 | * big of a problem [and we can't make it an spinlock | ||
129 | * because other parts need to take it and sleep] . | ||
130 | * | ||
131 | * @usb_hcd is refcounted, so it won't dissapear under us | ||
132 | * and before killing a host, the polling of the root hub | ||
133 | * would be stopped anyway. | ||
134 | */ | ||
135 | int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) | ||
136 | { | ||
137 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
138 | size_t cnt, size; | ||
139 | unsigned long *buf = (unsigned long *) _buf; | ||
140 | |||
141 | d_fnstart(1, wusbhc->dev, "(wusbhc %p)\n", wusbhc); | ||
142 | /* WE DON'T LOCK, see comment */ | ||
143 | size = wusbhc->ports_max + 1 /* hub bit */; | ||
144 | size = (size + 8 - 1) / 8; /* round to bytes */ | ||
145 | for (cnt = 0; cnt < wusbhc->ports_max; cnt++) | ||
146 | if (wusb_port_by_idx(wusbhc, cnt)->change) | ||
147 | set_bit(cnt + 1, buf); | ||
148 | else | ||
149 | clear_bit(cnt + 1, buf); | ||
150 | d_fnend(1, wusbhc->dev, "(wusbhc %p) %u, buffer:\n", wusbhc, (int)size); | ||
151 | d_dump(1, wusbhc->dev, _buf, size); | ||
152 | return size; | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); | ||
155 | |||
156 | /* | ||
157 | * Return the hub's desciptor | ||
158 | * | ||
159 | * NOTE: almost cut and paste from ehci-hub.c | ||
160 | * | ||
161 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked | ||
162 | */ | ||
163 | static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, | ||
164 | u16 wIndex, | ||
165 | struct usb_hub_descriptor *descr, | ||
166 | u16 wLength) | ||
167 | { | ||
168 | u16 temp = 1 + (wusbhc->ports_max / 8); | ||
169 | u8 length = 7 + 2 * temp; | ||
170 | |||
171 | if (wLength < length) | ||
172 | return -ENOSPC; | ||
173 | descr->bDescLength = 7 + 2 * temp; | ||
174 | descr->bDescriptorType = 0x29; /* HUB type */ | ||
175 | descr->bNbrPorts = wusbhc->ports_max; | ||
176 | descr->wHubCharacteristics = cpu_to_le16( | ||
177 | 0x00 /* All ports power at once */ | ||
178 | | 0x00 /* not part of compound device */ | ||
179 | | 0x10 /* No overcurrent protection */ | ||
180 | | 0x00 /* 8 FS think time FIXME ?? */ | ||
181 | | 0x00); /* No port indicators */ | ||
182 | descr->bPwrOn2PwrGood = 0; | ||
183 | descr->bHubContrCurrent = 0; | ||
184 | /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ | ||
185 | memset(&descr->bitmap[0], 0, temp); | ||
186 | memset(&descr->bitmap[temp], 0xff, temp); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Clear a hub feature | ||
192 | * | ||
193 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
194 | * | ||
195 | * Nothing to do, so no locking needed ;) | ||
196 | */ | ||
197 | static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) | ||
198 | { | ||
199 | int result; | ||
200 | struct device *dev = wusbhc->dev; | ||
201 | |||
202 | d_fnstart(4, dev, "(%p, feature 0x%04u)\n", wusbhc, feature); | ||
203 | switch (feature) { | ||
204 | case C_HUB_LOCAL_POWER: | ||
205 | /* FIXME: maybe plug bit 0 to the power input status, | ||
206 | * if any? | ||
207 | * see wusbhc_rh_get_hub_status() */ | ||
208 | case C_HUB_OVER_CURRENT: | ||
209 | result = 0; | ||
210 | break; | ||
211 | default: | ||
212 | result = -EPIPE; | ||
213 | } | ||
214 | d_fnend(4, dev, "(%p, feature 0x%04u), %d\n", wusbhc, feature, result); | ||
215 | return result; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Return hub status (it is always zero...) | ||
220 | * | ||
221 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
222 | * | ||
223 | * Nothing to do, so no locking needed ;) | ||
224 | */ | ||
225 | static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf, | ||
226 | u16 wLength) | ||
227 | { | ||
228 | /* FIXME: maybe plug bit 0 to the power input status (if any)? */ | ||
229 | *buf = 0; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Set a port feature | ||
235 | * | ||
236 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
237 | */ | ||
238 | static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, | ||
239 | u8 selector, u8 port_idx) | ||
240 | { | ||
241 | int result = -EINVAL; | ||
242 | struct device *dev = wusbhc->dev; | ||
243 | |||
244 | d_fnstart(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d)\n", | ||
245 | feature, selector, port_idx); | ||
246 | |||
247 | if (port_idx > wusbhc->ports_max) | ||
248 | goto error; | ||
249 | |||
250 | switch (feature) { | ||
251 | /* According to USB2.0[11.24.2.13]p2, these features | ||
252 | * are not required to be implemented. */ | ||
253 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
254 | case USB_PORT_FEAT_C_ENABLE: | ||
255 | case USB_PORT_FEAT_C_SUSPEND: | ||
256 | case USB_PORT_FEAT_C_CONNECTION: | ||
257 | case USB_PORT_FEAT_C_RESET: | ||
258 | result = 0; | ||
259 | break; | ||
260 | |||
261 | case USB_PORT_FEAT_POWER: | ||
262 | /* No such thing, but we fake it works */ | ||
263 | mutex_lock(&wusbhc->mutex); | ||
264 | wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER; | ||
265 | mutex_unlock(&wusbhc->mutex); | ||
266 | result = 0; | ||
267 | break; | ||
268 | case USB_PORT_FEAT_RESET: | ||
269 | result = wusbhc_rh_port_reset(wusbhc, port_idx); | ||
270 | break; | ||
271 | case USB_PORT_FEAT_ENABLE: | ||
272 | case USB_PORT_FEAT_SUSPEND: | ||
273 | dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n", | ||
274 | port_idx, feature, selector); | ||
275 | result = -ENOSYS; | ||
276 | break; | ||
277 | default: | ||
278 | dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n", | ||
279 | port_idx, feature, selector); | ||
280 | result = -EPIPE; | ||
281 | break; | ||
282 | } | ||
283 | error: | ||
284 | d_fnend(4, dev, "(feat 0x%04u, selector 0x%u, port_idx %d) = %d\n", | ||
285 | feature, selector, port_idx, result); | ||
286 | return result; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * Clear a port feature... | ||
291 | * | ||
292 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
293 | */ | ||
294 | static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, | ||
295 | u8 selector, u8 port_idx) | ||
296 | { | ||
297 | int result = -EINVAL; | ||
298 | struct device *dev = wusbhc->dev; | ||
299 | |||
300 | d_fnstart(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d)\n", | ||
301 | wusbhc, feature, selector, port_idx); | ||
302 | |||
303 | if (port_idx > wusbhc->ports_max) | ||
304 | goto error; | ||
305 | |||
306 | mutex_lock(&wusbhc->mutex); | ||
307 | result = 0; | ||
308 | switch (feature) { | ||
309 | case USB_PORT_FEAT_POWER: /* fake port always on */ | ||
310 | /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ | ||
311 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
312 | break; | ||
313 | case USB_PORT_FEAT_C_RESET: | ||
314 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET; | ||
315 | break; | ||
316 | case USB_PORT_FEAT_C_CONNECTION: | ||
317 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION; | ||
318 | break; | ||
319 | case USB_PORT_FEAT_ENABLE: | ||
320 | __wusbhc_dev_disable(wusbhc, port_idx); | ||
321 | break; | ||
322 | case USB_PORT_FEAT_C_ENABLE: | ||
323 | wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE; | ||
324 | break; | ||
325 | case USB_PORT_FEAT_SUSPEND: | ||
326 | case USB_PORT_FEAT_C_SUSPEND: | ||
327 | case 0xffff: /* ??? FIXME */ | ||
328 | dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", | ||
329 | port_idx, feature, selector); | ||
330 | /* dump_stack(); */ | ||
331 | result = -ENOSYS; | ||
332 | break; | ||
333 | default: | ||
334 | dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n", | ||
335 | port_idx, feature, selector); | ||
336 | result = -EPIPE; | ||
337 | break; | ||
338 | } | ||
339 | mutex_unlock(&wusbhc->mutex); | ||
340 | error: | ||
341 | d_fnend(4, dev, "(wusbhc %p feat 0x%04x selector %d port_idx %d) = " | ||
342 | "%d\n", wusbhc, feature, selector, port_idx, result); | ||
343 | return result; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Return the port's status | ||
348 | * | ||
349 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
350 | */ | ||
351 | static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, | ||
352 | u32 *_buf, u16 wLength) | ||
353 | { | ||
354 | int result = -EINVAL; | ||
355 | u16 *buf = (u16 *) _buf; | ||
356 | |||
357 | d_fnstart(1, wusbhc->dev, "(wusbhc %p port_idx %u wLength %u)\n", | ||
358 | wusbhc, port_idx, wLength); | ||
359 | if (port_idx > wusbhc->ports_max) | ||
360 | goto error; | ||
361 | mutex_lock(&wusbhc->mutex); | ||
362 | buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status); | ||
363 | buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change); | ||
364 | result = 0; | ||
365 | mutex_unlock(&wusbhc->mutex); | ||
366 | error: | ||
367 | d_fnend(1, wusbhc->dev, "(wusbhc %p) = %d, buffer:\n", wusbhc, result); | ||
368 | d_dump(1, wusbhc->dev, _buf, wLength); | ||
369 | return result; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Entry point for Root Hub operations | ||
374 | * | ||
375 | * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. | ||
376 | */ | ||
377 | int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue, | ||
378 | u16 wIndex, char *buf, u16 wLength) | ||
379 | { | ||
380 | int result = -ENOSYS; | ||
381 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
382 | |||
383 | switch (reqntype) { | ||
384 | case GetHubDescriptor: | ||
385 | result = wusbhc_rh_get_hub_descr( | ||
386 | wusbhc, wValue, wIndex, | ||
387 | (struct usb_hub_descriptor *) buf, wLength); | ||
388 | break; | ||
389 | case ClearHubFeature: | ||
390 | result = wusbhc_rh_clear_hub_feat(wusbhc, wValue); | ||
391 | break; | ||
392 | case GetHubStatus: | ||
393 | result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength); | ||
394 | break; | ||
395 | |||
396 | case SetPortFeature: | ||
397 | result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8, | ||
398 | (wIndex & 0xff) - 1); | ||
399 | break; | ||
400 | case ClearPortFeature: | ||
401 | result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8, | ||
402 | (wIndex & 0xff) - 1); | ||
403 | break; | ||
404 | case GetPortStatus: | ||
405 | result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1, | ||
406 | (u32 *)buf, wLength); | ||
407 | break; | ||
408 | |||
409 | case SetHubFeature: | ||
410 | default: | ||
411 | dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) " | ||
412 | "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype, | ||
413 | wValue, wIndex, buf, wLength); | ||
414 | /* dump_stack(); */ | ||
415 | result = -ENOSYS; | ||
416 | } | ||
417 | return result; | ||
418 | } | ||
419 | EXPORT_SYMBOL_GPL(wusbhc_rh_control); | ||
420 | |||
421 | int wusbhc_rh_suspend(struct usb_hcd *usb_hcd) | ||
422 | { | ||
423 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
424 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
425 | usb_hcd, wusbhc); | ||
426 | /* dump_stack(); */ | ||
427 | return -ENOSYS; | ||
428 | } | ||
429 | EXPORT_SYMBOL_GPL(wusbhc_rh_suspend); | ||
430 | |||
431 | int wusbhc_rh_resume(struct usb_hcd *usb_hcd) | ||
432 | { | ||
433 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
434 | dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, | ||
435 | usb_hcd, wusbhc); | ||
436 | /* dump_stack(); */ | ||
437 | return -ENOSYS; | ||
438 | } | ||
439 | EXPORT_SYMBOL_GPL(wusbhc_rh_resume); | ||
440 | |||
441 | int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx) | ||
442 | { | ||
443 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
444 | dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n", | ||
445 | __func__, usb_hcd, wusbhc, port_idx); | ||
446 | WARN_ON(1); | ||
447 | return -ENOSYS; | ||
448 | } | ||
449 | EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset); | ||
450 | |||
451 | static void wusb_port_init(struct wusb_port *port) | ||
452 | { | ||
453 | port->status |= USB_PORT_STAT_HIGH_SPEED; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * Alloc fake port specific fields and status. | ||
458 | */ | ||
459 | int wusbhc_rh_create(struct wusbhc *wusbhc) | ||
460 | { | ||
461 | int result = -ENOMEM; | ||
462 | size_t port_size, itr; | ||
463 | port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]); | ||
464 | wusbhc->port = kzalloc(port_size, GFP_KERNEL); | ||
465 | if (wusbhc->port == NULL) | ||
466 | goto error_port_alloc; | ||
467 | for (itr = 0; itr < wusbhc->ports_max; itr++) | ||
468 | wusb_port_init(&wusbhc->port[itr]); | ||
469 | result = 0; | ||
470 | error_port_alloc: | ||
471 | return result; | ||
472 | } | ||
473 | |||
474 | void wusbhc_rh_destroy(struct wusbhc *wusbhc) | ||
475 | { | ||
476 | kfree(wusbhc->port); | ||
477 | } | ||
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c new file mode 100644 index 000000000000..a101cad6a8d4 --- /dev/null +++ b/drivers/usb/wusbcore/security.c | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Security support: encryption enablement, etc | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/usb/ch9.h> | ||
27 | #include <linux/random.h> | ||
28 | #include "wusbhc.h" | ||
29 | |||
30 | /* | ||
31 | * DEBUG & SECURITY WARNING!!!! | ||
32 | * | ||
33 | * If you enable this past 1, the debug code will weaken the | ||
34 | * cryptographic safety of the system (on purpose, for debugging). | ||
35 | * | ||
36 | * Weaken means: | ||
37 | * we print secret keys and intermediate values all the way, | ||
38 | */ | ||
39 | #undef D_LOCAL | ||
40 | #define D_LOCAL 2 | ||
41 | #include <linux/uwb/debug.h> | ||
42 | |||
43 | static void wusbhc_set_gtk_callback(struct urb *urb); | ||
44 | static void wusbhc_gtk_rekey_done_work(struct work_struct *work); | ||
45 | |||
46 | int wusbhc_sec_create(struct wusbhc *wusbhc) | ||
47 | { | ||
48 | wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data); | ||
49 | wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY; | ||
50 | wusbhc->gtk.descr.bReserved = 0; | ||
51 | |||
52 | wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, | ||
53 | WUSB_KEY_INDEX_ORIGINATOR_HOST); | ||
54 | |||
55 | INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | |||
61 | /* Called when the HC is destroyed */ | ||
62 | void wusbhc_sec_destroy(struct wusbhc *wusbhc) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | |||
67 | /** | ||
68 | * wusbhc_next_tkid - generate a new, currently unused, TKID | ||
69 | * @wusbhc: the WUSB host controller | ||
70 | * @wusb_dev: the device whose PTK the TKID is for | ||
71 | * (or NULL for a TKID for a GTK) | ||
72 | * | ||
73 | * The generated TKID consist of two parts: the device's authenicated | ||
74 | * address (or 0 or a GTK); and an incrementing number. This ensures | ||
75 | * that TKIDs cannot be shared between devices and by the time the | ||
76 | * incrementing number wraps around the older TKIDs will no longer be | ||
77 | * in use (a maximum of two keys may be active at any one time). | ||
78 | */ | ||
79 | static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
80 | { | ||
81 | u32 *tkid; | ||
82 | u32 addr; | ||
83 | |||
84 | if (wusb_dev == NULL) { | ||
85 | tkid = &wusbhc->gtk_tkid; | ||
86 | addr = 0; | ||
87 | } else { | ||
88 | tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid; | ||
89 | addr = wusb_dev->addr & 0x7f; | ||
90 | } | ||
91 | |||
92 | *tkid = (addr << 8) | ((*tkid + 1) & 0xff); | ||
93 | |||
94 | return *tkid; | ||
95 | } | ||
96 | |||
97 | static void wusbhc_generate_gtk(struct wusbhc *wusbhc) | ||
98 | { | ||
99 | const size_t key_size = sizeof(wusbhc->gtk.data); | ||
100 | u32 tkid; | ||
101 | |||
102 | tkid = wusbhc_next_tkid(wusbhc, NULL); | ||
103 | |||
104 | wusbhc->gtk.descr.tTKID[0] = (tkid >> 0) & 0xff; | ||
105 | wusbhc->gtk.descr.tTKID[1] = (tkid >> 8) & 0xff; | ||
106 | wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff; | ||
107 | |||
108 | get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * wusbhc_sec_start - start the security management process | ||
113 | * @wusbhc: the WUSB host controller | ||
114 | * | ||
115 | * Generate and set an initial GTK on the host controller. | ||
116 | * | ||
117 | * Called when the HC is started. | ||
118 | */ | ||
119 | int wusbhc_sec_start(struct wusbhc *wusbhc) | ||
120 | { | ||
121 | const size_t key_size = sizeof(wusbhc->gtk.data); | ||
122 | int result; | ||
123 | |||
124 | wusbhc_generate_gtk(wusbhc); | ||
125 | |||
126 | result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, | ||
127 | &wusbhc->gtk.descr.bKeyData, key_size); | ||
128 | if (result < 0) | ||
129 | dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n", | ||
130 | result); | ||
131 | |||
132 | return result; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * wusbhc_sec_stop - stop the security management process | ||
137 | * @wusbhc: the WUSB host controller | ||
138 | * | ||
139 | * Wait for any pending GTK rekeys to stop. | ||
140 | */ | ||
141 | void wusbhc_sec_stop(struct wusbhc *wusbhc) | ||
142 | { | ||
143 | cancel_work_sync(&wusbhc->gtk_rekey_done_work); | ||
144 | } | ||
145 | |||
146 | |||
147 | /** @returns encryption type name */ | ||
148 | const char *wusb_et_name(u8 x) | ||
149 | { | ||
150 | switch (x) { | ||
151 | case USB_ENC_TYPE_UNSECURE: return "unsecure"; | ||
152 | case USB_ENC_TYPE_WIRED: return "wired"; | ||
153 | case USB_ENC_TYPE_CCM_1: return "CCM-1"; | ||
154 | case USB_ENC_TYPE_RSA_1: return "RSA-1"; | ||
155 | default: return "unknown"; | ||
156 | } | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(wusb_et_name); | ||
159 | |||
160 | /* | ||
161 | * Set the device encryption method | ||
162 | * | ||
163 | * We tell the device which encryption method to use; we do this when | ||
164 | * setting up the device's security. | ||
165 | */ | ||
166 | static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value) | ||
167 | { | ||
168 | int result; | ||
169 | struct device *dev = &usb_dev->dev; | ||
170 | struct wusb_dev *wusb_dev = usb_dev->wusb_dev; | ||
171 | |||
172 | if (value) { | ||
173 | value = wusb_dev->ccm1_etd.bEncryptionValue; | ||
174 | } else { | ||
175 | /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */ | ||
176 | value = 0; | ||
177 | } | ||
178 | /* Set device's */ | ||
179 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
180 | USB_REQ_SET_ENCRYPTION, | ||
181 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
182 | value, 0, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
183 | if (result < 0) | ||
184 | dev_err(dev, "Can't set device's WUSB encryption to " | ||
185 | "%s (value %d): %d\n", | ||
186 | wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType), | ||
187 | wusb_dev->ccm1_etd.bEncryptionValue, result); | ||
188 | return result; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Set the GTK to be used by a device. | ||
193 | * | ||
194 | * The device must be authenticated. | ||
195 | */ | ||
196 | static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) | ||
197 | { | ||
198 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
199 | |||
200 | return usb_control_msg( | ||
201 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
202 | USB_REQ_SET_DESCRIPTOR, | ||
203 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
204 | USB_DT_KEY << 8 | wusbhc->gtk_index, 0, | ||
205 | &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, | ||
206 | 1000); | ||
207 | } | ||
208 | |||
209 | |||
210 | /* FIXME: prototype for adding security */ | ||
211 | int wusb_dev_sec_add(struct wusbhc *wusbhc, | ||
212 | struct usb_device *usb_dev, struct wusb_dev *wusb_dev) | ||
213 | { | ||
214 | int result, bytes, secd_size; | ||
215 | struct device *dev = &usb_dev->dev; | ||
216 | struct usb_security_descriptor secd; | ||
217 | const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; | ||
218 | void *secd_buf; | ||
219 | const void *itr, *top; | ||
220 | char buf[64]; | ||
221 | |||
222 | d_fnstart(3, dev, "(usb_dev %p, wusb_dev %p)\n", usb_dev, wusb_dev); | ||
223 | result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, | ||
224 | 0, &secd, sizeof(secd)); | ||
225 | if (result < sizeof(secd)) { | ||
226 | dev_err(dev, "Can't read security descriptor or " | ||
227 | "not enough data: %d\n", result); | ||
228 | goto error_secd; | ||
229 | } | ||
230 | secd_size = le16_to_cpu(secd.wTotalLength); | ||
231 | d_printf(5, dev, "got %d bytes of sec descriptor, total is %d\n", | ||
232 | result, secd_size); | ||
233 | secd_buf = kmalloc(secd_size, GFP_KERNEL); | ||
234 | if (secd_buf == NULL) { | ||
235 | dev_err(dev, "Can't allocate space for security descriptors\n"); | ||
236 | goto error_secd_alloc; | ||
237 | } | ||
238 | result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, | ||
239 | 0, secd_buf, secd_size); | ||
240 | if (result < secd_size) { | ||
241 | dev_err(dev, "Can't read security descriptor or " | ||
242 | "not enough data: %d\n", result); | ||
243 | goto error_secd_all; | ||
244 | } | ||
245 | d_printf(5, dev, "got %d bytes of sec descriptors\n", result); | ||
246 | bytes = 0; | ||
247 | itr = secd_buf + sizeof(secd); | ||
248 | top = secd_buf + result; | ||
249 | while (itr < top) { | ||
250 | etd = itr; | ||
251 | if (top - itr < sizeof(*etd)) { | ||
252 | dev_err(dev, "BUG: bad device security descriptor; " | ||
253 | "not enough data (%zu vs %zu bytes left)\n", | ||
254 | top - itr, sizeof(*etd)); | ||
255 | break; | ||
256 | } | ||
257 | if (etd->bLength < sizeof(*etd)) { | ||
258 | dev_err(dev, "BUG: bad device encryption descriptor; " | ||
259 | "descriptor is too short " | ||
260 | "(%u vs %zu needed)\n", | ||
261 | etd->bLength, sizeof(*etd)); | ||
262 | break; | ||
263 | } | ||
264 | itr += etd->bLength; | ||
265 | bytes += snprintf(buf + bytes, sizeof(buf) - bytes, | ||
266 | "%s (0x%02x/%02x) ", | ||
267 | wusb_et_name(etd->bEncryptionType), | ||
268 | etd->bEncryptionValue, etd->bAuthKeyIndex); | ||
269 | if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1) | ||
270 | ccm1_etd = etd; | ||
271 | } | ||
272 | /* This code only supports CCM1 as of now. */ | ||
273 | /* FIXME: user has to choose which sec mode to use? | ||
274 | * In theory we want CCM */ | ||
275 | if (ccm1_etd == NULL) { | ||
276 | dev_err(dev, "WUSB device doesn't support CCM1 encryption, " | ||
277 | "can't use!\n"); | ||
278 | result = -EINVAL; | ||
279 | goto error_no_ccm1; | ||
280 | } | ||
281 | wusb_dev->ccm1_etd = *ccm1_etd; | ||
282 | dev_info(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", | ||
283 | buf, wusb_et_name(ccm1_etd->bEncryptionType), | ||
284 | ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); | ||
285 | result = 0; | ||
286 | kfree(secd_buf); | ||
287 | out: | ||
288 | d_fnend(3, dev, "(usb_dev %p, wusb_dev %p) = %d\n", | ||
289 | usb_dev, wusb_dev, result); | ||
290 | return result; | ||
291 | |||
292 | |||
293 | error_no_ccm1: | ||
294 | error_secd_all: | ||
295 | kfree(secd_buf); | ||
296 | error_secd_alloc: | ||
297 | error_secd: | ||
298 | goto out; | ||
299 | } | ||
300 | |||
301 | void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) | ||
302 | { | ||
303 | /* Nothing so far */ | ||
304 | } | ||
305 | |||
306 | static void hs_printk(unsigned level, struct device *dev, | ||
307 | struct usb_handshake *hs) | ||
308 | { | ||
309 | d_printf(level, dev, | ||
310 | " bMessageNumber: %u\n" | ||
311 | " bStatus: %u\n" | ||
312 | " tTKID: %02x %02x %02x\n" | ||
313 | " CDID: %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
314 | " %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
315 | " nonce: %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
316 | " %02x %02x %02x %02x %02x %02x %02x %02x\n" | ||
317 | " MIC: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
318 | hs->bMessageNumber, hs->bStatus, | ||
319 | hs->tTKID[2], hs->tTKID[1], hs->tTKID[0], | ||
320 | hs->CDID[0], hs->CDID[1], hs->CDID[2], hs->CDID[3], | ||
321 | hs->CDID[4], hs->CDID[5], hs->CDID[6], hs->CDID[7], | ||
322 | hs->CDID[8], hs->CDID[9], hs->CDID[10], hs->CDID[11], | ||
323 | hs->CDID[12], hs->CDID[13], hs->CDID[14], hs->CDID[15], | ||
324 | hs->nonce[0], hs->nonce[1], hs->nonce[2], hs->nonce[3], | ||
325 | hs->nonce[4], hs->nonce[5], hs->nonce[6], hs->nonce[7], | ||
326 | hs->nonce[8], hs->nonce[9], hs->nonce[10], hs->nonce[11], | ||
327 | hs->nonce[12], hs->nonce[13], hs->nonce[14], hs->nonce[15], | ||
328 | hs->MIC[0], hs->MIC[1], hs->MIC[2], hs->MIC[3], | ||
329 | hs->MIC[4], hs->MIC[5], hs->MIC[6], hs->MIC[7]); | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * Update the address of an unauthenticated WUSB device | ||
334 | * | ||
335 | * Once we have successfully authenticated, we take it to addr0 state | ||
336 | * and then to a normal address. | ||
337 | * | ||
338 | * Before the device's address (as known by it) was usb_dev->devnum | | ||
339 | * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum. | ||
340 | */ | ||
341 | static int wusb_dev_update_address(struct wusbhc *wusbhc, | ||
342 | struct wusb_dev *wusb_dev) | ||
343 | { | ||
344 | int result = -ENOMEM; | ||
345 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
346 | struct device *dev = &usb_dev->dev; | ||
347 | u8 new_address = wusb_dev->addr & 0x7F; | ||
348 | |||
349 | /* Set address 0 */ | ||
350 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
351 | USB_REQ_SET_ADDRESS, 0, | ||
352 | 0, 0, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
353 | if (result < 0) { | ||
354 | dev_err(dev, "auth failed: can't set address 0: %d\n", | ||
355 | result); | ||
356 | goto error_addr0; | ||
357 | } | ||
358 | result = wusb_set_dev_addr(wusbhc, wusb_dev, 0); | ||
359 | if (result < 0) | ||
360 | goto error_addr0; | ||
361 | usb_ep0_reinit(usb_dev); | ||
362 | |||
363 | /* Set new (authenticated) address. */ | ||
364 | result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
365 | USB_REQ_SET_ADDRESS, 0, | ||
366 | new_address, 0, NULL, 0, | ||
367 | 1000 /* FIXME: arbitrary */); | ||
368 | if (result < 0) { | ||
369 | dev_err(dev, "auth failed: can't set address %u: %d\n", | ||
370 | new_address, result); | ||
371 | goto error_addr; | ||
372 | } | ||
373 | result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address); | ||
374 | if (result < 0) | ||
375 | goto error_addr; | ||
376 | usb_ep0_reinit(usb_dev); | ||
377 | usb_dev->authenticated = 1; | ||
378 | error_addr: | ||
379 | error_addr0: | ||
380 | return result; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * | ||
385 | * | ||
386 | */ | ||
387 | /* FIXME: split and cleanup */ | ||
388 | int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, | ||
389 | struct wusb_ckhdid *ck) | ||
390 | { | ||
391 | int result = -ENOMEM; | ||
392 | struct usb_device *usb_dev = wusb_dev->usb_dev; | ||
393 | struct device *dev = &usb_dev->dev; | ||
394 | u32 tkid; | ||
395 | __le32 tkid_le; | ||
396 | struct usb_handshake *hs; | ||
397 | struct aes_ccm_nonce ccm_n; | ||
398 | u8 mic[8]; | ||
399 | struct wusb_keydvt_in keydvt_in; | ||
400 | struct wusb_keydvt_out keydvt_out; | ||
401 | |||
402 | hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL); | ||
403 | if (hs == NULL) { | ||
404 | dev_err(dev, "can't allocate handshake data\n"); | ||
405 | goto error_kzalloc; | ||
406 | } | ||
407 | |||
408 | /* We need to turn encryption before beginning the 4way | ||
409 | * hshake (WUSB1.0[.3.2.2]) */ | ||
410 | result = wusb_dev_set_encryption(usb_dev, 1); | ||
411 | if (result < 0) | ||
412 | goto error_dev_set_encryption; | ||
413 | |||
414 | tkid = wusbhc_next_tkid(wusbhc, wusb_dev); | ||
415 | tkid_le = cpu_to_le32(tkid); | ||
416 | |||
417 | hs[0].bMessageNumber = 1; | ||
418 | hs[0].bStatus = 0; | ||
419 | memcpy(hs[0].tTKID, &tkid_le, sizeof(hs[0].tTKID)); | ||
420 | hs[0].bReserved = 0; | ||
421 | memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID)); | ||
422 | get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce)); | ||
423 | memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */ | ||
424 | |||
425 | d_printf(1, dev, "I: sending hs1:\n"); | ||
426 | hs_printk(2, dev, &hs[0]); | ||
427 | |||
428 | result = usb_control_msg( | ||
429 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
430 | USB_REQ_SET_HANDSHAKE, | ||
431 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
432 | 1, 0, &hs[0], sizeof(hs[0]), 1000 /* FIXME: arbitrary */); | ||
433 | if (result < 0) { | ||
434 | dev_err(dev, "Handshake1: request failed: %d\n", result); | ||
435 | goto error_hs1; | ||
436 | } | ||
437 | |||
438 | /* Handshake 2, from the device -- need to verify fields */ | ||
439 | result = usb_control_msg( | ||
440 | usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
441 | USB_REQ_GET_HANDSHAKE, | ||
442 | USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
443 | 2, 0, &hs[1], sizeof(hs[1]), 1000 /* FIXME: arbitrary */); | ||
444 | if (result < 0) { | ||
445 | dev_err(dev, "Handshake2: request failed: %d\n", result); | ||
446 | goto error_hs2; | ||
447 | } | ||
448 | d_printf(1, dev, "got HS2:\n"); | ||
449 | hs_printk(2, dev, &hs[1]); | ||
450 | |||
451 | result = -EINVAL; | ||
452 | if (hs[1].bMessageNumber != 2) { | ||
453 | dev_err(dev, "Handshake2 failed: bad message number %u\n", | ||
454 | hs[1].bMessageNumber); | ||
455 | goto error_hs2; | ||
456 | } | ||
457 | if (hs[1].bStatus != 0) { | ||
458 | dev_err(dev, "Handshake2 failed: bad status %u\n", | ||
459 | hs[1].bStatus); | ||
460 | goto error_hs2; | ||
461 | } | ||
462 | if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) { | ||
463 | dev_err(dev, "Handshake2 failed: TKID mismatch " | ||
464 | "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n", | ||
465 | hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2], | ||
466 | hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]); | ||
467 | goto error_hs2; | ||
468 | } | ||
469 | if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) { | ||
470 | dev_err(dev, "Handshake2 failed: CDID mismatch\n"); | ||
471 | goto error_hs2; | ||
472 | } | ||
473 | |||
474 | /* Setup the CCM nonce */ | ||
475 | memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */ | ||
476 | memcpy(ccm_n.tkid, &tkid_le, sizeof(ccm_n.tkid)); | ||
477 | ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr; | ||
478 | ccm_n.dest_addr.data[0] = wusb_dev->addr; | ||
479 | ccm_n.dest_addr.data[1] = 0; | ||
480 | |||
481 | /* Derive the KCK and PTK from CK, the CCM, H and D nonces */ | ||
482 | memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce)); | ||
483 | memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce)); | ||
484 | result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in); | ||
485 | if (result < 0) { | ||
486 | dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n", | ||
487 | result); | ||
488 | goto error_hs2; | ||
489 | } | ||
490 | d_printf(2, dev, "KCK:\n"); | ||
491 | d_dump(2, dev, keydvt_out.kck, sizeof(keydvt_out.kck)); | ||
492 | d_printf(2, dev, "PTK:\n"); | ||
493 | d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
494 | |||
495 | /* Compute MIC and verify it */ | ||
496 | result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]); | ||
497 | if (result < 0) { | ||
498 | dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n", | ||
499 | result); | ||
500 | goto error_hs2; | ||
501 | } | ||
502 | |||
503 | d_printf(2, dev, "MIC:\n"); | ||
504 | d_dump(2, dev, mic, sizeof(mic)); | ||
505 | if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) { | ||
506 | dev_err(dev, "Handshake2 failed: MIC mismatch\n"); | ||
507 | goto error_hs2; | ||
508 | } | ||
509 | |||
510 | /* Send Handshake3 */ | ||
511 | hs[2].bMessageNumber = 3; | ||
512 | hs[2].bStatus = 0; | ||
513 | memcpy(hs[2].tTKID, &tkid_le, sizeof(hs[2].tTKID)); | ||
514 | hs[2].bReserved = 0; | ||
515 | memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID)); | ||
516 | memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce)); | ||
517 | result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]); | ||
518 | if (result < 0) { | ||
519 | dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n", | ||
520 | result); | ||
521 | goto error_hs2; | ||
522 | } | ||
523 | |||
524 | d_printf(1, dev, "I: sending hs3:\n"); | ||
525 | hs_printk(2, dev, &hs[2]); | ||
526 | |||
527 | result = usb_control_msg( | ||
528 | usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
529 | USB_REQ_SET_HANDSHAKE, | ||
530 | USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | ||
531 | 3, 0, &hs[2], sizeof(hs[2]), 1000 /* FIXME: arbitrary */); | ||
532 | if (result < 0) { | ||
533 | dev_err(dev, "Handshake3: request failed: %d\n", result); | ||
534 | goto error_hs3; | ||
535 | } | ||
536 | |||
537 | d_printf(1, dev, "I: turning on encryption on host for device\n"); | ||
538 | d_dump(2, dev, keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
539 | result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid, | ||
540 | keydvt_out.ptk, sizeof(keydvt_out.ptk)); | ||
541 | if (result < 0) | ||
542 | goto error_wusbhc_set_ptk; | ||
543 | |||
544 | d_printf(1, dev, "I: setting a GTK\n"); | ||
545 | result = wusb_dev_set_gtk(wusbhc, wusb_dev); | ||
546 | if (result < 0) { | ||
547 | dev_err(dev, "Set GTK for device: request failed: %d\n", | ||
548 | result); | ||
549 | goto error_wusbhc_set_gtk; | ||
550 | } | ||
551 | |||
552 | /* Update the device's address from unauth to auth */ | ||
553 | if (usb_dev->authenticated == 0) { | ||
554 | d_printf(1, dev, "I: updating addres to auth from non-auth\n"); | ||
555 | result = wusb_dev_update_address(wusbhc, wusb_dev); | ||
556 | if (result < 0) | ||
557 | goto error_dev_update_address; | ||
558 | } | ||
559 | result = 0; | ||
560 | d_printf(1, dev, "I: 4way handshke done, device authenticated\n"); | ||
561 | |||
562 | error_dev_update_address: | ||
563 | error_wusbhc_set_gtk: | ||
564 | error_wusbhc_set_ptk: | ||
565 | error_hs3: | ||
566 | error_hs2: | ||
567 | error_hs1: | ||
568 | memset(hs, 0, 3*sizeof(hs[0])); | ||
569 | memset(&keydvt_out, 0, sizeof(keydvt_out)); | ||
570 | memset(&keydvt_in, 0, sizeof(keydvt_in)); | ||
571 | memset(&ccm_n, 0, sizeof(ccm_n)); | ||
572 | memset(mic, 0, sizeof(mic)); | ||
573 | if (result < 0) { | ||
574 | /* error path */ | ||
575 | wusb_dev_set_encryption(usb_dev, 0); | ||
576 | } | ||
577 | error_dev_set_encryption: | ||
578 | kfree(hs); | ||
579 | error_kzalloc: | ||
580 | return result; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * Once all connected and authenticated devices have received the new | ||
585 | * GTK, switch the host to using it. | ||
586 | */ | ||
587 | static void wusbhc_gtk_rekey_done_work(struct work_struct *work) | ||
588 | { | ||
589 | struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work); | ||
590 | size_t key_size = sizeof(wusbhc->gtk.data); | ||
591 | |||
592 | mutex_lock(&wusbhc->mutex); | ||
593 | |||
594 | if (--wusbhc->pending_set_gtks == 0) | ||
595 | wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); | ||
596 | |||
597 | mutex_unlock(&wusbhc->mutex); | ||
598 | } | ||
599 | |||
600 | static void wusbhc_set_gtk_callback(struct urb *urb) | ||
601 | { | ||
602 | struct wusbhc *wusbhc = urb->context; | ||
603 | |||
604 | queue_work(wusbd, &wusbhc->gtk_rekey_done_work); | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * wusbhc_gtk_rekey - generate and distribute a new GTK | ||
609 | * @wusbhc: the WUSB host controller | ||
610 | * | ||
611 | * Generate a new GTK and distribute it to all connected and | ||
612 | * authenticated devices. When all devices have the new GTK, the host | ||
613 | * starts using it. | ||
614 | * | ||
615 | * This must be called after every device disconnect (see [WUSB] | ||
616 | * section 6.2.11.2). | ||
617 | */ | ||
618 | void wusbhc_gtk_rekey(struct wusbhc *wusbhc) | ||
619 | { | ||
620 | static const size_t key_size = sizeof(wusbhc->gtk.data); | ||
621 | int p; | ||
622 | |||
623 | wusbhc_generate_gtk(wusbhc); | ||
624 | |||
625 | for (p = 0; p < wusbhc->ports_max; p++) { | ||
626 | struct wusb_dev *wusb_dev; | ||
627 | |||
628 | wusb_dev = wusbhc->port[p].wusb_dev; | ||
629 | if (!wusb_dev || !wusb_dev->usb_dev | !wusb_dev->usb_dev->authenticated) | ||
630 | continue; | ||
631 | |||
632 | usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev, | ||
633 | usb_sndctrlpipe(wusb_dev->usb_dev, 0), | ||
634 | (void *)wusb_dev->set_gtk_req, | ||
635 | &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, | ||
636 | wusbhc_set_gtk_callback, wusbhc); | ||
637 | if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0) | ||
638 | wusbhc->pending_set_gtks++; | ||
639 | } | ||
640 | if (wusbhc->pending_set_gtks == 0) | ||
641 | wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); | ||
642 | } | ||
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c new file mode 100644 index 000000000000..9d04722415bb --- /dev/null +++ b/drivers/usb/wusbcore/wa-hc.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Wire Adapter Host Controller Driver | ||
3 | * Common items to HWA and DWA based HCDs | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | #include "wusbhc.h" | ||
26 | #include "wa-hc.h" | ||
27 | |||
28 | /** | ||
29 | * Assumes | ||
30 | * | ||
31 | * wa->usb_dev and wa->usb_iface initialized and refcounted, | ||
32 | * wa->wa_descr initialized. | ||
33 | */ | ||
34 | int wa_create(struct wahc *wa, struct usb_interface *iface) | ||
35 | { | ||
36 | int result; | ||
37 | struct device *dev = &iface->dev; | ||
38 | |||
39 | result = wa_rpipes_create(wa); | ||
40 | if (result < 0) | ||
41 | goto error_rpipes_create; | ||
42 | /* Fill up Data Transfer EP pointers */ | ||
43 | wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc; | ||
44 | wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; | ||
45 | wa->xfer_result_size = le16_to_cpu(wa->dti_epd->wMaxPacketSize); | ||
46 | wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL); | ||
47 | if (wa->xfer_result == NULL) | ||
48 | goto error_xfer_result_alloc; | ||
49 | result = wa_nep_create(wa, iface); | ||
50 | if (result < 0) { | ||
51 | dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n", | ||
52 | result); | ||
53 | goto error_nep_create; | ||
54 | } | ||
55 | return 0; | ||
56 | |||
57 | error_nep_create: | ||
58 | kfree(wa->xfer_result); | ||
59 | error_xfer_result_alloc: | ||
60 | wa_rpipes_destroy(wa); | ||
61 | error_rpipes_create: | ||
62 | return result; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(wa_create); | ||
65 | |||
66 | |||
67 | void __wa_destroy(struct wahc *wa) | ||
68 | { | ||
69 | if (wa->dti_urb) { | ||
70 | usb_kill_urb(wa->dti_urb); | ||
71 | usb_put_urb(wa->dti_urb); | ||
72 | usb_kill_urb(wa->buf_in_urb); | ||
73 | usb_put_urb(wa->buf_in_urb); | ||
74 | } | ||
75 | kfree(wa->xfer_result); | ||
76 | wa_nep_destroy(wa); | ||
77 | wa_rpipes_destroy(wa); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(__wa_destroy); | ||
80 | |||
81 | /** | ||
82 | * wa_reset_all - reset the WA device | ||
83 | * @wa: the WA to be reset | ||
84 | * | ||
85 | * For HWAs the radio controller and all other PALs are also reset. | ||
86 | */ | ||
87 | void wa_reset_all(struct wahc *wa) | ||
88 | { | ||
89 | /* FIXME: assuming HWA. */ | ||
90 | wusbhc_reset_all(wa->wusb); | ||
91 | } | ||
92 | |||
93 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
94 | MODULE_DESCRIPTION("Wireless USB Wire Adapter core"); | ||
95 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h new file mode 100644 index 000000000000..586d350cdb4d --- /dev/null +++ b/drivers/usb/wusbcore/wa-hc.h | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * HWA Host Controller Driver | ||
3 | * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8]) | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This driver implements a USB Host Controller (struct usb_hcd) for a | ||
24 | * Wireless USB Host Controller based on the Wireless USB 1.0 | ||
25 | * Host-Wire-Adapter specification (in layman terms, a USB-dongle that | ||
26 | * implements a Wireless USB host). | ||
27 | * | ||
28 | * Check out the Design-overview.txt file in the source documentation | ||
29 | * for other details on the implementation. | ||
30 | * | ||
31 | * Main blocks: | ||
32 | * | ||
33 | * driver glue with the driver API, workqueue daemon | ||
34 | * | ||
35 | * lc RC instance life cycle management (create, destroy...) | ||
36 | * | ||
37 | * hcd glue with the USB API Host Controller Interface API. | ||
38 | * | ||
39 | * nep Notification EndPoint managent: collect notifications | ||
40 | * and queue them with the workqueue daemon. | ||
41 | * | ||
42 | * Handle notifications as coming from the NEP. Sends them | ||
43 | * off others to their respective modules (eg: connect, | ||
44 | * disconnect and reset go to devconnect). | ||
45 | * | ||
46 | * rpipe Remote Pipe management; rpipe is what we use to write | ||
47 | * to an endpoint on a WUSB device that is connected to a | ||
48 | * HWA RC. | ||
49 | * | ||
50 | * xfer Transfer managment -- this is all the code that gets a | ||
51 | * buffer and pushes it to a device (or viceversa). * | ||
52 | * | ||
53 | * Some day a lot of this code will be shared between this driver and | ||
54 | * the drivers for DWA (xfer, rpipe). | ||
55 | * | ||
56 | * All starts at driver.c:hwahc_probe(), when one of this guys is | ||
57 | * connected. hwahc_disconnect() stops it. | ||
58 | * | ||
59 | * During operation, the main driver is devices connecting or | ||
60 | * disconnecting. They cause the HWA RC to send notifications into | ||
61 | * nep.c:hwahc_nep_cb() that will dispatch them to | ||
62 | * notif.c:wa_notif_dispatch(). From there they will fan to cause | ||
63 | * device connects, disconnects, etc. | ||
64 | * | ||
65 | * Note much of the activity is difficult to follow. For example a | ||
66 | * device connect goes to devconnect, which will cause the "fake" root | ||
67 | * hub port to show a connect and stop there. Then khubd will notice | ||
68 | * and call into the rh.c:hwahc_rc_port_reset() code to authenticate | ||
69 | * the device (and this might require user intervention) and enable | ||
70 | * the port. | ||
71 | * | ||
72 | * We also have a timer workqueue going from devconnect.c that | ||
73 | * schedules in hwahc_devconnect_create(). | ||
74 | * | ||
75 | * The rest of the traffic is in the usual entry points of a USB HCD, | ||
76 | * which are hooked up in driver.c:hwahc_rc_driver, and defined in | ||
77 | * hcd.c. | ||
78 | */ | ||
79 | |||
80 | #ifndef __HWAHC_INTERNAL_H__ | ||
81 | #define __HWAHC_INTERNAL_H__ | ||
82 | |||
83 | #include <linux/completion.h> | ||
84 | #include <linux/usb.h> | ||
85 | #include <linux/mutex.h> | ||
86 | #include <linux/spinlock.h> | ||
87 | #include <linux/uwb.h> | ||
88 | #include <linux/usb/wusb.h> | ||
89 | #include <linux/usb/wusb-wa.h> | ||
90 | |||
91 | struct wusbhc; | ||
92 | struct wahc; | ||
93 | extern void wa_urb_enqueue_run(struct work_struct *ws); | ||
94 | |||
95 | /** | ||
96 | * RPipe instance | ||
97 | * | ||
98 | * @descr's fields are kept in LE, as we need to send it back and | ||
99 | * forth. | ||
100 | * | ||
101 | * @wa is referenced when set | ||
102 | * | ||
103 | * @segs_available is the number of requests segments that still can | ||
104 | * be submitted to the controller without overloading | ||
105 | * it. It is initialized to descr->wRequests when | ||
106 | * aiming. | ||
107 | * | ||
108 | * A rpipe supports a max of descr->wRequests at the same time; before | ||
109 | * submitting seg_lock has to be taken. If segs_avail > 0, then we can | ||
110 | * submit; if not, we have to queue them. | ||
111 | */ | ||
112 | struct wa_rpipe { | ||
113 | struct kref refcnt; | ||
114 | struct usb_rpipe_descriptor descr; | ||
115 | struct usb_host_endpoint *ep; | ||
116 | struct wahc *wa; | ||
117 | spinlock_t seg_lock; | ||
118 | struct list_head seg_list; | ||
119 | atomic_t segs_available; | ||
120 | u8 buffer[1]; /* For reads/writes on USB */ | ||
121 | }; | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Instance of a HWA Host Controller | ||
126 | * | ||
127 | * Except where a more specific lock/mutex applies or atomic, all | ||
128 | * fields protected by @mutex. | ||
129 | * | ||
130 | * @wa_descr Can be accessed without locking because it is in | ||
131 | * the same area where the device descriptors were | ||
132 | * read, so it is guaranteed to exist umodified while | ||
133 | * the device exists. | ||
134 | * | ||
135 | * Endianess has been converted to CPU's. | ||
136 | * | ||
137 | * @nep_* can be accessed without locking as its processing is | ||
138 | * serialized; we submit a NEP URB and it comes to | ||
139 | * hwahc_nep_cb(), which won't issue another URB until it is | ||
140 | * done processing it. | ||
141 | * | ||
142 | * @xfer_list: | ||
143 | * | ||
144 | * List of active transfers to verify existence from a xfer id | ||
145 | * gotten from the xfer result message. Can't use urb->list because | ||
146 | * it goes by endpoint, and we don't know the endpoint at the time | ||
147 | * when we get the xfer result message. We can't really rely on the | ||
148 | * pointer (will have to change for 64 bits) as the xfer id is 32 bits. | ||
149 | * | ||
150 | * @xfer_delayed_list: List of transfers that need to be started | ||
151 | * (with a workqueue, because they were | ||
152 | * submitted from an atomic context). | ||
153 | * | ||
154 | * FIXME: this needs to be layered up: a wusbhc layer (for sharing | ||
155 | * comonalities with WHCI), a wa layer (for sharing | ||
156 | * comonalities with DWA-RC). | ||
157 | */ | ||
158 | struct wahc { | ||
159 | struct usb_device *usb_dev; | ||
160 | struct usb_interface *usb_iface; | ||
161 | |||
162 | /* HC to deliver notifications */ | ||
163 | union { | ||
164 | struct wusbhc *wusb; | ||
165 | struct dwahc *dwa; | ||
166 | }; | ||
167 | |||
168 | const struct usb_endpoint_descriptor *dto_epd, *dti_epd; | ||
169 | const struct usb_wa_descriptor *wa_descr; | ||
170 | |||
171 | struct urb *nep_urb; /* Notification EndPoint [lockless] */ | ||
172 | struct edc nep_edc; | ||
173 | void *nep_buffer; | ||
174 | size_t nep_buffer_size; | ||
175 | |||
176 | atomic_t notifs_queued; | ||
177 | |||
178 | u16 rpipes; | ||
179 | unsigned long *rpipe_bm; /* rpipe usage bitmap */ | ||
180 | spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ | ||
181 | struct mutex rpipe_mutex; /* assigning resources to endpoints */ | ||
182 | |||
183 | struct urb *dti_urb; /* URB for reading xfer results */ | ||
184 | struct urb *buf_in_urb; /* URB for reading data in */ | ||
185 | struct edc dti_edc; /* DTI error density counter */ | ||
186 | struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ | ||
187 | size_t xfer_result_size; | ||
188 | |||
189 | s32 status; /* For reading status */ | ||
190 | |||
191 | struct list_head xfer_list; | ||
192 | struct list_head xfer_delayed_list; | ||
193 | spinlock_t xfer_list_lock; | ||
194 | struct work_struct xfer_work; | ||
195 | atomic_t xfer_id_count; | ||
196 | }; | ||
197 | |||
198 | |||
199 | extern int wa_create(struct wahc *wa, struct usb_interface *iface); | ||
200 | extern void __wa_destroy(struct wahc *wa); | ||
201 | void wa_reset_all(struct wahc *wa); | ||
202 | |||
203 | |||
204 | /* Miscellaneous constants */ | ||
205 | enum { | ||
206 | /** Max number of EPROTO errors we tolerate on the NEP in a | ||
207 | * period of time */ | ||
208 | HWAHC_EPROTO_MAX = 16, | ||
209 | /** Period of time for EPROTO errors (in jiffies) */ | ||
210 | HWAHC_EPROTO_PERIOD = 4 * HZ, | ||
211 | }; | ||
212 | |||
213 | |||
214 | /* Notification endpoint handling */ | ||
215 | extern int wa_nep_create(struct wahc *, struct usb_interface *); | ||
216 | extern void wa_nep_destroy(struct wahc *); | ||
217 | |||
218 | static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask) | ||
219 | { | ||
220 | struct urb *urb = wa->nep_urb; | ||
221 | urb->transfer_buffer = wa->nep_buffer; | ||
222 | urb->transfer_buffer_length = wa->nep_buffer_size; | ||
223 | return usb_submit_urb(urb, gfp_mask); | ||
224 | } | ||
225 | |||
226 | static inline void wa_nep_disarm(struct wahc *wa) | ||
227 | { | ||
228 | usb_kill_urb(wa->nep_urb); | ||
229 | } | ||
230 | |||
231 | |||
232 | /* RPipes */ | ||
233 | static inline void wa_rpipe_init(struct wahc *wa) | ||
234 | { | ||
235 | spin_lock_init(&wa->rpipe_bm_lock); | ||
236 | mutex_init(&wa->rpipe_mutex); | ||
237 | } | ||
238 | |||
239 | static inline void wa_init(struct wahc *wa) | ||
240 | { | ||
241 | edc_init(&wa->nep_edc); | ||
242 | atomic_set(&wa->notifs_queued, 0); | ||
243 | wa_rpipe_init(wa); | ||
244 | edc_init(&wa->dti_edc); | ||
245 | INIT_LIST_HEAD(&wa->xfer_list); | ||
246 | INIT_LIST_HEAD(&wa->xfer_delayed_list); | ||
247 | spin_lock_init(&wa->xfer_list_lock); | ||
248 | INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); | ||
249 | atomic_set(&wa->xfer_id_count, 1); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * Destroy a pipe (when refcount drops to zero) | ||
254 | * | ||
255 | * Assumes it has been moved to the "QUIESCING" state. | ||
256 | */ | ||
257 | struct wa_xfer; | ||
258 | extern void rpipe_destroy(struct kref *_rpipe); | ||
259 | static inline | ||
260 | void __rpipe_get(struct wa_rpipe *rpipe) | ||
261 | { | ||
262 | kref_get(&rpipe->refcnt); | ||
263 | } | ||
264 | extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *, | ||
265 | struct urb *, gfp_t); | ||
266 | static inline void rpipe_put(struct wa_rpipe *rpipe) | ||
267 | { | ||
268 | kref_put(&rpipe->refcnt, rpipe_destroy); | ||
269 | |||
270 | } | ||
271 | extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); | ||
272 | extern int wa_rpipes_create(struct wahc *); | ||
273 | extern void wa_rpipes_destroy(struct wahc *); | ||
274 | static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) | ||
275 | { | ||
276 | atomic_dec(&rpipe->segs_available); | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * Returns true if the rpipe is ready to submit more segments. | ||
281 | */ | ||
282 | static inline int rpipe_avail_inc(struct wa_rpipe *rpipe) | ||
283 | { | ||
284 | return atomic_inc_return(&rpipe->segs_available) > 0 | ||
285 | && !list_empty(&rpipe->seg_list); | ||
286 | } | ||
287 | |||
288 | |||
289 | /* Transferring data */ | ||
290 | extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, | ||
291 | struct urb *, gfp_t); | ||
292 | extern int wa_urb_dequeue(struct wahc *, struct urb *); | ||
293 | extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); | ||
294 | |||
295 | |||
296 | /* Misc | ||
297 | * | ||
298 | * FIXME: Refcounting for the actual @hwahc object is not correct; I | ||
299 | * mean, this should be refcounting on the HCD underneath, but | ||
300 | * it is not. In any case, the semantics for HCD refcounting | ||
301 | * are *weird*...on refcount reaching zero it just frees | ||
302 | * it...no RC specific function is called...unless I miss | ||
303 | * something. | ||
304 | * | ||
305 | * FIXME: has to go away in favour of an 'struct' hcd based sollution | ||
306 | */ | ||
307 | static inline struct wahc *wa_get(struct wahc *wa) | ||
308 | { | ||
309 | usb_get_intf(wa->usb_iface); | ||
310 | return wa; | ||
311 | } | ||
312 | |||
313 | static inline void wa_put(struct wahc *wa) | ||
314 | { | ||
315 | usb_put_intf(wa->usb_iface); | ||
316 | } | ||
317 | |||
318 | |||
319 | static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature) | ||
320 | { | ||
321 | return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
322 | op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE, | ||
323 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
324 | feature, | ||
325 | wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
326 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
327 | } | ||
328 | |||
329 | |||
330 | static inline int __wa_set_feature(struct wahc *wa, u16 feature) | ||
331 | { | ||
332 | return __wa_feature(wa, 1, feature); | ||
333 | } | ||
334 | |||
335 | |||
336 | static inline int __wa_clear_feature(struct wahc *wa, u16 feature) | ||
337 | { | ||
338 | return __wa_feature(wa, 0, feature); | ||
339 | } | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Return the status of a Wire Adapter | ||
344 | * | ||
345 | * @wa: Wire Adapter instance | ||
346 | * @returns < 0 errno code on error, or status bitmap as described | ||
347 | * in WUSB1.0[8.3.1.6]. | ||
348 | * | ||
349 | * NOTE: need malloc, some arches don't take USB from the stack | ||
350 | */ | ||
351 | static inline | ||
352 | s32 __wa_get_status(struct wahc *wa) | ||
353 | { | ||
354 | s32 result; | ||
355 | result = usb_control_msg( | ||
356 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
357 | USB_REQ_GET_STATUS, | ||
358 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
359 | 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
360 | &wa->status, sizeof(wa->status), | ||
361 | 1000 /* FIXME: arbitrary */); | ||
362 | if (result >= 0) | ||
363 | result = wa->status; | ||
364 | return result; | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Waits until the Wire Adapter's status matches @mask/@value | ||
370 | * | ||
371 | * @wa: Wire Adapter instance. | ||
372 | * @returns < 0 errno code on error, otherwise status. | ||
373 | * | ||
374 | * Loop until the WAs status matches the mask and value (status & mask | ||
375 | * == value). Timeout if it doesn't happen. | ||
376 | * | ||
377 | * FIXME: is there an official specification on how long status | ||
378 | * changes can take? | ||
379 | */ | ||
380 | static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value) | ||
381 | { | ||
382 | s32 result; | ||
383 | unsigned loops = 10; | ||
384 | do { | ||
385 | msleep(50); | ||
386 | result = __wa_get_status(wa); | ||
387 | if ((result & mask) == value) | ||
388 | break; | ||
389 | if (loops-- == 0) { | ||
390 | result = -ETIMEDOUT; | ||
391 | break; | ||
392 | } | ||
393 | } while (result >= 0); | ||
394 | return result; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */ | ||
399 | static inline int __wa_stop(struct wahc *wa) | ||
400 | { | ||
401 | int result; | ||
402 | struct device *dev = &wa->usb_iface->dev; | ||
403 | |||
404 | result = __wa_clear_feature(wa, WA_ENABLE); | ||
405 | if (result < 0 && result != -ENODEV) { | ||
406 | dev_err(dev, "error commanding HC to stop: %d\n", result); | ||
407 | goto out; | ||
408 | } | ||
409 | result = __wa_wait_status(wa, WA_ENABLE, 0); | ||
410 | if (result < 0 && result != -ENODEV) | ||
411 | dev_err(dev, "error waiting for HC to stop: %d\n", result); | ||
412 | out: | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | |||
417 | #endif /* #ifndef __HWAHC_INTERNAL_H__ */ | ||
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c new file mode 100644 index 000000000000..3f542990c73f --- /dev/null +++ b/drivers/usb/wusbcore/wa-nep.c | |||
@@ -0,0 +1,310 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) | ||
3 | * Notification EndPoint support | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This part takes care of getting the notification from the hw | ||
24 | * only and dispatching through wusbwad into | ||
25 | * wa_notif_dispatch. Handling is done there. | ||
26 | * | ||
27 | * WA notifications are limited in size; most of them are three or | ||
28 | * four bytes long, and the longest is the HWA Device Notification, | ||
29 | * which would not exceed 38 bytes (DNs are limited in payload to 32 | ||
30 | * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA | ||
31 | * header (WUSB1.0[8.5.4.2]). | ||
32 | * | ||
33 | * It is not clear if more than one Device Notification can be packed | ||
34 | * in a HWA Notification, I assume no because of the wording in | ||
35 | * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could | ||
36 | * get is 256 bytes (as the bLength field is a byte). | ||
37 | * | ||
38 | * So what we do is we have this buffer and read into it; when a | ||
39 | * notification arrives we schedule work to a specific, single thread | ||
40 | * workqueue (so notifications are serialized) and copy the | ||
41 | * notification data. After scheduling the work, we rearm the read from | ||
42 | * the notification endpoint. | ||
43 | * | ||
44 | * Entry points here are: | ||
45 | * | ||
46 | * wa_nep_[create|destroy]() To initialize/release this subsystem | ||
47 | * | ||
48 | * wa_nep_cb() Callback for the notification | ||
49 | * endpoint; when data is ready, this | ||
50 | * does the dispatching. | ||
51 | */ | ||
52 | #include <linux/workqueue.h> | ||
53 | #include <linux/ctype.h> | ||
54 | #include <linux/uwb/debug.h> | ||
55 | #include "wa-hc.h" | ||
56 | #include "wusbhc.h" | ||
57 | |||
58 | /* Structure for queueing notifications to the workqueue */ | ||
59 | struct wa_notif_work { | ||
60 | struct work_struct work; | ||
61 | struct wahc *wa; | ||
62 | size_t size; | ||
63 | u8 data[]; | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * Process incoming notifications from the WA's Notification EndPoint | ||
68 | * [the wuswad daemon, basically] | ||
69 | * | ||
70 | * @_nw: Pointer to a descriptor which has the pointer to the | ||
71 | * @wa, the size of the buffer and the work queue | ||
72 | * structure (so we can free all when done). | ||
73 | * @returns 0 if ok, < 0 errno code on error. | ||
74 | * | ||
75 | * All notifications follow the same format; they need to start with a | ||
76 | * 'struct wa_notif_hdr' header, so it is easy to parse through | ||
77 | * them. We just break the buffer in individual notifications (the | ||
78 | * standard doesn't say if it can be done or is forbidden, so we are | ||
79 | * cautious) and dispatch each. | ||
80 | * | ||
81 | * So the handling layers are is: | ||
82 | * | ||
83 | * WA specific notification (from NEP) | ||
84 | * Device Notification Received -> wa_handle_notif_dn() | ||
85 | * WUSB Device notification generic handling | ||
86 | * BPST Adjustment -> wa_handle_notif_bpst_adj() | ||
87 | * ... -> ... | ||
88 | * | ||
89 | * @wa has to be referenced | ||
90 | */ | ||
91 | static void wa_notif_dispatch(struct work_struct *ws) | ||
92 | { | ||
93 | void *itr; | ||
94 | u8 missing = 0; | ||
95 | struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, work); | ||
96 | struct wahc *wa = nw->wa; | ||
97 | struct wa_notif_hdr *notif_hdr; | ||
98 | size_t size; | ||
99 | |||
100 | struct device *dev = &wa->usb_iface->dev; | ||
101 | |||
102 | #if 0 | ||
103 | /* FIXME: need to check for this??? */ | ||
104 | if (usb_hcd->state == HC_STATE_QUIESCING) /* Going down? */ | ||
105 | goto out; /* screw it */ | ||
106 | #endif | ||
107 | atomic_dec(&wa->notifs_queued); /* Throttling ctl */ | ||
108 | dev = &wa->usb_iface->dev; | ||
109 | size = nw->size; | ||
110 | itr = nw->data; | ||
111 | |||
112 | while (size) { | ||
113 | if (size < sizeof(*notif_hdr)) { | ||
114 | missing = sizeof(*notif_hdr) - size; | ||
115 | goto exhausted_buffer; | ||
116 | } | ||
117 | notif_hdr = itr; | ||
118 | if (size < notif_hdr->bLength) | ||
119 | goto exhausted_buffer; | ||
120 | itr += notif_hdr->bLength; | ||
121 | size -= notif_hdr->bLength; | ||
122 | /* Dispatch the notification [don't use itr or size!] */ | ||
123 | switch (notif_hdr->bNotifyType) { | ||
124 | case HWA_NOTIF_DN: { | ||
125 | struct hwa_notif_dn *hwa_dn; | ||
126 | hwa_dn = container_of(notif_hdr, struct hwa_notif_dn, | ||
127 | hdr); | ||
128 | wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr, | ||
129 | hwa_dn->dndata, | ||
130 | notif_hdr->bLength - sizeof(*hwa_dn)); | ||
131 | break; | ||
132 | } | ||
133 | case WA_NOTIF_TRANSFER: | ||
134 | wa_handle_notif_xfer(wa, notif_hdr); | ||
135 | break; | ||
136 | case DWA_NOTIF_RWAKE: | ||
137 | case DWA_NOTIF_PORTSTATUS: | ||
138 | case HWA_NOTIF_BPST_ADJ: | ||
139 | /* FIXME: unimplemented WA NOTIFs */ | ||
140 | /* fallthru */ | ||
141 | default: | ||
142 | if (printk_ratelimit()) { | ||
143 | dev_err(dev, "HWA: unknown notification 0x%x, " | ||
144 | "%zu bytes; discarding\n", | ||
145 | notif_hdr->bNotifyType, | ||
146 | (size_t)notif_hdr->bLength); | ||
147 | dump_bytes(dev, notif_hdr, 16); | ||
148 | } | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | out: | ||
153 | wa_put(wa); | ||
154 | kfree(nw); | ||
155 | return; | ||
156 | |||
157 | /* THIS SHOULD NOT HAPPEN | ||
158 | * | ||
159 | * Buffer exahusted with partial data remaining; just warn and | ||
160 | * discard the data, as this should not happen. | ||
161 | */ | ||
162 | exhausted_buffer: | ||
163 | if (!printk_ratelimit()) | ||
164 | goto out; | ||
165 | dev_warn(dev, "HWA: device sent short notification, " | ||
166 | "%d bytes missing; discarding %d bytes.\n", | ||
167 | missing, (int)size); | ||
168 | dump_bytes(dev, itr, size); | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Deliver incoming WA notifications to the wusbwa workqueue | ||
174 | * | ||
175 | * @wa: Pointer the Wire Adapter Controller Data Streaming | ||
176 | * instance (part of an 'struct usb_hcd'). | ||
177 | * @size: Size of the received buffer | ||
178 | * @returns 0 if ok, < 0 errno code on error. | ||
179 | * | ||
180 | * The input buffer is @wa->nep_buffer, with @size bytes | ||
181 | * (guaranteed to fit in the allocated space, | ||
182 | * @wa->nep_buffer_size). | ||
183 | */ | ||
184 | static int wa_nep_queue(struct wahc *wa, size_t size) | ||
185 | { | ||
186 | int result = 0; | ||
187 | struct device *dev = &wa->usb_iface->dev; | ||
188 | struct wa_notif_work *nw; | ||
189 | |||
190 | /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */ | ||
191 | BUG_ON(size > wa->nep_buffer_size); | ||
192 | if (size == 0) | ||
193 | goto out; | ||
194 | if (atomic_read(&wa->notifs_queued) > 200) { | ||
195 | if (printk_ratelimit()) | ||
196 | dev_err(dev, "Too many notifications queued, " | ||
197 | "throttling back\n"); | ||
198 | goto out; | ||
199 | } | ||
200 | nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC); | ||
201 | if (nw == NULL) { | ||
202 | if (printk_ratelimit()) | ||
203 | dev_err(dev, "No memory to queue notification\n"); | ||
204 | goto out; | ||
205 | } | ||
206 | INIT_WORK(&nw->work, wa_notif_dispatch); | ||
207 | nw->wa = wa_get(wa); | ||
208 | nw->size = size; | ||
209 | memcpy(nw->data, wa->nep_buffer, size); | ||
210 | atomic_inc(&wa->notifs_queued); /* Throttling ctl */ | ||
211 | queue_work(wusbd, &nw->work); | ||
212 | out: | ||
213 | /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */ | ||
214 | return result; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Callback for the notification event endpoint | ||
219 | * | ||
220 | * Check's that everything is fine and then passes the data to be | ||
221 | * queued to the workqueue. | ||
222 | */ | ||
223 | static void wa_nep_cb(struct urb *urb) | ||
224 | { | ||
225 | int result; | ||
226 | struct wahc *wa = urb->context; | ||
227 | struct device *dev = &wa->usb_iface->dev; | ||
228 | |||
229 | switch (result = urb->status) { | ||
230 | case 0: | ||
231 | result = wa_nep_queue(wa, urb->actual_length); | ||
232 | if (result < 0) | ||
233 | dev_err(dev, "NEP: unable to process notification(s): " | ||
234 | "%d\n", result); | ||
235 | break; | ||
236 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
237 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
238 | case -ESHUTDOWN: | ||
239 | dev_dbg(dev, "NEP: going down %d\n", urb->status); | ||
240 | goto out; | ||
241 | default: /* On general errors, we retry unless it gets ugly */ | ||
242 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
243 | EDC_ERROR_TIMEFRAME)) { | ||
244 | dev_err(dev, "NEP: URB max acceptable errors " | ||
245 | "exceeded, resetting device\n"); | ||
246 | wa_reset_all(wa); | ||
247 | goto out; | ||
248 | } | ||
249 | dev_err(dev, "NEP: URB error %d\n", urb->status); | ||
250 | } | ||
251 | result = wa_nep_arm(wa, GFP_ATOMIC); | ||
252 | if (result < 0) { | ||
253 | dev_err(dev, "NEP: cannot submit URB: %d\n", result); | ||
254 | wa_reset_all(wa); | ||
255 | } | ||
256 | out: | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Initialize @wa's notification and event's endpoint stuff | ||
262 | * | ||
263 | * This includes the allocating the read buffer, the context ID | ||
264 | * allocation bitmap, the URB and submitting the URB. | ||
265 | */ | ||
266 | int wa_nep_create(struct wahc *wa, struct usb_interface *iface) | ||
267 | { | ||
268 | int result; | ||
269 | struct usb_endpoint_descriptor *epd; | ||
270 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
271 | struct device *dev = &iface->dev; | ||
272 | |||
273 | edc_init(&wa->nep_edc); | ||
274 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
275 | wa->nep_buffer_size = 1024; | ||
276 | wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL); | ||
277 | if (wa->nep_buffer == NULL) { | ||
278 | dev_err(dev, "Unable to allocate notification's read buffer\n"); | ||
279 | goto error_nep_buffer; | ||
280 | } | ||
281 | wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
282 | if (wa->nep_urb == NULL) { | ||
283 | dev_err(dev, "Unable to allocate notification URB\n"); | ||
284 | goto error_urb_alloc; | ||
285 | } | ||
286 | usb_fill_int_urb(wa->nep_urb, usb_dev, | ||
287 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
288 | wa->nep_buffer, wa->nep_buffer_size, | ||
289 | wa_nep_cb, wa, epd->bInterval); | ||
290 | result = wa_nep_arm(wa, GFP_KERNEL); | ||
291 | if (result < 0) { | ||
292 | dev_err(dev, "Cannot submit notification URB: %d\n", result); | ||
293 | goto error_nep_arm; | ||
294 | } | ||
295 | return 0; | ||
296 | |||
297 | error_nep_arm: | ||
298 | usb_free_urb(wa->nep_urb); | ||
299 | error_urb_alloc: | ||
300 | kfree(wa->nep_buffer); | ||
301 | error_nep_buffer: | ||
302 | return -ENOMEM; | ||
303 | } | ||
304 | |||
305 | void wa_nep_destroy(struct wahc *wa) | ||
306 | { | ||
307 | wa_nep_disarm(wa); | ||
308 | usb_free_urb(wa->nep_urb); | ||
309 | kfree(wa->nep_buffer); | ||
310 | } | ||
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c new file mode 100644 index 000000000000..f18e4aae66e9 --- /dev/null +++ b/drivers/usb/wusbcore/wa-rpipe.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter | ||
3 | * rpipe management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * RPIPE | ||
26 | * | ||
27 | * Targetted at different downstream endpoints | ||
28 | * | ||
29 | * Descriptor: use to config the remote pipe. | ||
30 | * | ||
31 | * The number of blocks could be dynamic (wBlocks in descriptor is | ||
32 | * 0)--need to schedule them then. | ||
33 | * | ||
34 | * Each bit in wa->rpipe_bm represents if an rpipe is being used or | ||
35 | * not. Rpipes are represented with a 'struct wa_rpipe' that is | ||
36 | * attached to the hcpriv member of a 'struct usb_host_endpoint'. | ||
37 | * | ||
38 | * When you need to xfer data to an endpoint, you get an rpipe for it | ||
39 | * with wa_ep_rpipe_get(), which gives you a reference to the rpipe | ||
40 | * and keeps a single one (the first one) with the endpoint. When you | ||
41 | * are done transferring, you drop that reference. At the end the | ||
42 | * rpipe is always allocated and bound to the endpoint. There it might | ||
43 | * be recycled when not used. | ||
44 | * | ||
45 | * Addresses: | ||
46 | * | ||
47 | * We use a 1:1 mapping mechanism between port address (0 based | ||
48 | * index, actually) and the address. The USB stack knows about this. | ||
49 | * | ||
50 | * USB Stack port number 4 (1 based) | ||
51 | * WUSB code port index 3 (0 based) | ||
52 | * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) | ||
53 | * | ||
54 | * Now, because we don't use the concept as default address exactly | ||
55 | * like the (wired) USB code does, we need to kind of skip it. So we | ||
56 | * never take addresses from the urb->pipe, but from the | ||
57 | * urb->dev->devnum, to make sure that we always have the right | ||
58 | * destination address. | ||
59 | */ | ||
60 | #include <linux/init.h> | ||
61 | #include <asm/atomic.h> | ||
62 | #include <linux/bitmap.h> | ||
63 | #include "wusbhc.h" | ||
64 | #include "wa-hc.h" | ||
65 | |||
66 | #define D_LOCAL 0 | ||
67 | #include <linux/uwb/debug.h> | ||
68 | |||
69 | |||
70 | static int __rpipe_get_descr(struct wahc *wa, | ||
71 | struct usb_rpipe_descriptor *descr, u16 index) | ||
72 | { | ||
73 | ssize_t result; | ||
74 | struct device *dev = &wa->usb_iface->dev; | ||
75 | |||
76 | /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() | ||
77 | * function because the arguments are different. | ||
78 | */ | ||
79 | d_printf(1, dev, "rpipe %u: get descr\n", index); | ||
80 | result = usb_control_msg( | ||
81 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
82 | USB_REQ_GET_DESCRIPTOR, | ||
83 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
84 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
85 | 1000 /* FIXME: arbitrary */); | ||
86 | if (result < 0) { | ||
87 | dev_err(dev, "rpipe %u: get descriptor failed: %d\n", | ||
88 | index, (int)result); | ||
89 | goto error; | ||
90 | } | ||
91 | if (result < sizeof(*descr)) { | ||
92 | dev_err(dev, "rpipe %u: got short descriptor " | ||
93 | "(%zd vs %zd bytes needed)\n", | ||
94 | index, result, sizeof(*descr)); | ||
95 | result = -EINVAL; | ||
96 | goto error; | ||
97 | } | ||
98 | result = 0; | ||
99 | |||
100 | error: | ||
101 | return result; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * | ||
106 | * The descriptor is assumed to be properly initialized (ie: you got | ||
107 | * it through __rpipe_get_descr()). | ||
108 | */ | ||
109 | static int __rpipe_set_descr(struct wahc *wa, | ||
110 | struct usb_rpipe_descriptor *descr, u16 index) | ||
111 | { | ||
112 | ssize_t result; | ||
113 | struct device *dev = &wa->usb_iface->dev; | ||
114 | |||
115 | /* we cannot use the usb_get_descriptor() function because the | ||
116 | * arguments are different. | ||
117 | */ | ||
118 | d_printf(1, dev, "rpipe %u: set descr\n", index); | ||
119 | result = usb_control_msg( | ||
120 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
121 | USB_REQ_SET_DESCRIPTOR, | ||
122 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
123 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
124 | HZ / 10); | ||
125 | if (result < 0) { | ||
126 | dev_err(dev, "rpipe %u: set descriptor failed: %d\n", | ||
127 | index, (int)result); | ||
128 | goto error; | ||
129 | } | ||
130 | if (result < sizeof(*descr)) { | ||
131 | dev_err(dev, "rpipe %u: sent short descriptor " | ||
132 | "(%zd vs %zd bytes required)\n", | ||
133 | index, result, sizeof(*descr)); | ||
134 | result = -EINVAL; | ||
135 | goto error; | ||
136 | } | ||
137 | result = 0; | ||
138 | |||
139 | error: | ||
140 | return result; | ||
141 | |||
142 | } | ||
143 | |||
144 | static void rpipe_init(struct wa_rpipe *rpipe) | ||
145 | { | ||
146 | kref_init(&rpipe->refcnt); | ||
147 | spin_lock_init(&rpipe->seg_lock); | ||
148 | INIT_LIST_HEAD(&rpipe->seg_list); | ||
149 | } | ||
150 | |||
151 | static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
156 | rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx); | ||
157 | if (rpipe_idx < wa->rpipes) | ||
158 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
159 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
160 | |||
161 | return rpipe_idx; | ||
162 | } | ||
163 | |||
164 | static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx) | ||
165 | { | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
169 | clear_bit(rpipe_idx, wa->rpipe_bm); | ||
170 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
171 | } | ||
172 | |||
173 | void rpipe_destroy(struct kref *_rpipe) | ||
174 | { | ||
175 | struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); | ||
176 | u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
177 | d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
178 | if (rpipe->ep) | ||
179 | rpipe->ep->hcpriv = NULL; | ||
180 | rpipe_put_idx(rpipe->wa, index); | ||
181 | wa_put(rpipe->wa); | ||
182 | kfree(rpipe); | ||
183 | d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
184 | } | ||
185 | EXPORT_SYMBOL_GPL(rpipe_destroy); | ||
186 | |||
187 | /* | ||
188 | * Locate an idle rpipe, create an structure for it and return it | ||
189 | * | ||
190 | * @wa is referenced and unlocked | ||
191 | * @crs enum rpipe_attr, required endpoint characteristics | ||
192 | * | ||
193 | * The rpipe can be used only sequentially (not in parallel). | ||
194 | * | ||
195 | * The rpipe is moved into the "ready" state. | ||
196 | */ | ||
197 | static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, | ||
198 | gfp_t gfp) | ||
199 | { | ||
200 | int result; | ||
201 | unsigned rpipe_idx; | ||
202 | struct wa_rpipe *rpipe; | ||
203 | struct device *dev = &wa->usb_iface->dev; | ||
204 | |||
205 | d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs); | ||
206 | rpipe = kzalloc(sizeof(*rpipe), gfp); | ||
207 | if (rpipe == NULL) | ||
208 | return -ENOMEM; | ||
209 | rpipe_init(rpipe); | ||
210 | |||
211 | /* Look for an idle pipe */ | ||
212 | for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) { | ||
213 | rpipe_idx = rpipe_get_idx(wa, rpipe_idx); | ||
214 | if (rpipe_idx >= wa->rpipes) /* no more pipes :( */ | ||
215 | break; | ||
216 | result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx); | ||
217 | if (result < 0) | ||
218 | dev_err(dev, "Can't get descriptor for rpipe %u: %d\n", | ||
219 | rpipe_idx, result); | ||
220 | else if ((rpipe->descr.bmCharacteristics & crs) != 0) | ||
221 | goto found; | ||
222 | rpipe_put_idx(wa, rpipe_idx); | ||
223 | } | ||
224 | *prpipe = NULL; | ||
225 | kfree(rpipe); | ||
226 | d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs); | ||
227 | return -ENXIO; | ||
228 | |||
229 | found: | ||
230 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
231 | rpipe->wa = wa_get(wa); | ||
232 | *prpipe = rpipe; | ||
233 | d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int __rpipe_reset(struct wahc *wa, unsigned index) | ||
238 | { | ||
239 | int result; | ||
240 | struct device *dev = &wa->usb_iface->dev; | ||
241 | |||
242 | d_printf(1, dev, "rpipe %u: reset\n", index); | ||
243 | result = usb_control_msg( | ||
244 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
245 | USB_REQ_RPIPE_RESET, | ||
246 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
247 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
248 | if (result < 0) | ||
249 | dev_err(dev, "rpipe %u: reset failed: %d\n", | ||
250 | index, result); | ||
251 | return result; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Fake companion descriptor for ep0 | ||
256 | * | ||
257 | * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl | ||
258 | */ | ||
259 | static struct usb_wireless_ep_comp_descriptor epc0 = { | ||
260 | .bLength = sizeof(epc0), | ||
261 | .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, | ||
262 | /* .bMaxBurst = 1, */ | ||
263 | .bMaxSequence = 31, | ||
264 | }; | ||
265 | |||
266 | /* | ||
267 | * Look for EP companion descriptor | ||
268 | * | ||
269 | * Get there, look for Inara in the endpoint's extra descriptors | ||
270 | */ | ||
271 | static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( | ||
272 | struct device *dev, struct usb_host_endpoint *ep) | ||
273 | { | ||
274 | void *itr; | ||
275 | size_t itr_size; | ||
276 | struct usb_descriptor_header *hdr; | ||
277 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
278 | |||
279 | d_fnstart(3, dev, "(ep %p)\n", ep); | ||
280 | if (ep->desc.bEndpointAddress == 0) { | ||
281 | epcd = &epc0; | ||
282 | goto out; | ||
283 | } | ||
284 | itr = ep->extra; | ||
285 | itr_size = ep->extralen; | ||
286 | epcd = NULL; | ||
287 | while (itr_size > 0) { | ||
288 | if (itr_size < sizeof(*hdr)) { | ||
289 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors " | ||
290 | "at offset %zu: only %zu bytes left\n", | ||
291 | ep->desc.bEndpointAddress, | ||
292 | itr - (void *) ep->extra, itr_size); | ||
293 | break; | ||
294 | } | ||
295 | hdr = itr; | ||
296 | if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) { | ||
297 | epcd = itr; | ||
298 | break; | ||
299 | } | ||
300 | if (hdr->bLength > itr_size) { | ||
301 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor " | ||
302 | "at offset %zu (type 0x%02x) " | ||
303 | "length %d but only %zu bytes left\n", | ||
304 | ep->desc.bEndpointAddress, | ||
305 | itr - (void *) ep->extra, hdr->bDescriptorType, | ||
306 | hdr->bLength, itr_size); | ||
307 | break; | ||
308 | } | ||
309 | itr += hdr->bLength; | ||
310 | itr_size -= hdr->bDescriptorType; | ||
311 | } | ||
312 | out: | ||
313 | d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd); | ||
314 | return epcd; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * Aim an rpipe to its device & endpoint destination | ||
319 | * | ||
320 | * Make sure we change the address to unauthenticathed if the device | ||
321 | * is WUSB and it is not authenticated. | ||
322 | */ | ||
323 | static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, | ||
324 | struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp) | ||
325 | { | ||
326 | int result = -ENOMSG; /* better code for lack of companion? */ | ||
327 | struct device *dev = &wa->usb_iface->dev; | ||
328 | struct usb_device *usb_dev = urb->dev; | ||
329 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
330 | u8 unauth; | ||
331 | |||
332 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
333 | rpipe, wa, ep, urb); | ||
334 | epcd = rpipe_epc_find(dev, ep); | ||
335 | if (epcd == NULL) { | ||
336 | dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", | ||
337 | ep->desc.bEndpointAddress); | ||
338 | goto error; | ||
339 | } | ||
340 | unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0; | ||
341 | __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
342 | atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); | ||
343 | /* FIXME: block allocation system; request with queuing and timeout */ | ||
344 | /* FIXME: compute so seg_size > ep->maxpktsize */ | ||
345 | rpipe->descr.wBlocks = cpu_to_le16(16); /* given */ | ||
346 | /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ | ||
347 | rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); | ||
348 | rpipe->descr.bHSHubAddress = 0; /* reserved: zero */ | ||
349 | rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); | ||
350 | /* FIXME: use maximum speed as supported or recommended by device */ | ||
351 | rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? | ||
352 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200; | ||
353 | d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", | ||
354 | urb->dev->devnum, urb->dev->devnum | unauth, | ||
355 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
356 | usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); | ||
357 | /* see security.c:wusb_update_address() */ | ||
358 | if (unlikely(urb->dev->devnum == 0x80)) | ||
359 | rpipe->descr.bDeviceAddress = 0; | ||
360 | else | ||
361 | rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; | ||
362 | rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress; | ||
363 | /* FIXME: bDataSequence */ | ||
364 | rpipe->descr.bDataSequence = 0; | ||
365 | /* FIXME: dwCurrentWindow */ | ||
366 | rpipe->descr.dwCurrentWindow = cpu_to_le32(1); | ||
367 | /* FIXME: bMaxDataSequence */ | ||
368 | rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; | ||
369 | rpipe->descr.bInterval = ep->desc.bInterval; | ||
370 | /* FIXME: bOverTheAirInterval */ | ||
371 | rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ | ||
372 | /* FIXME: xmit power & preamble blah blah */ | ||
373 | rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; | ||
374 | /* rpipe->descr.bmCharacteristics RO */ | ||
375 | /* FIXME: bmRetryOptions */ | ||
376 | rpipe->descr.bmRetryOptions = 15; | ||
377 | /* FIXME: use for assessing link quality? */ | ||
378 | rpipe->descr.wNumTransactionErrors = 0; | ||
379 | result = __rpipe_set_descr(wa, &rpipe->descr, | ||
380 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
381 | if (result < 0) { | ||
382 | dev_err(dev, "Cannot aim rpipe: %d\n", result); | ||
383 | goto error; | ||
384 | } | ||
385 | result = 0; | ||
386 | error: | ||
387 | d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n", | ||
388 | rpipe, wa, ep, urb, result); | ||
389 | return result; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Check an aimed rpipe to make sure it points to where we want | ||
394 | * | ||
395 | * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth | ||
396 | * space; when it is like that, we or 0x80 to make an unauth address. | ||
397 | */ | ||
398 | static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, | ||
399 | const struct usb_host_endpoint *ep, | ||
400 | const struct urb *urb, gfp_t gfp) | ||
401 | { | ||
402 | int result = 0; /* better code for lack of companion? */ | ||
403 | struct device *dev = &wa->usb_iface->dev; | ||
404 | struct usb_device *usb_dev = urb->dev; | ||
405 | u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; | ||
406 | u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); | ||
407 | |||
408 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
409 | rpipe, wa, ep, urb); | ||
410 | #define AIM_CHECK(rdf, val, text) \ | ||
411 | do { \ | ||
412 | if (rpipe->descr.rdf != (val)) { \ | ||
413 | dev_err(dev, \ | ||
414 | "rpipe aim discrepancy: " #rdf " " text "\n", \ | ||
415 | rpipe->descr.rdf, (val)); \ | ||
416 | result = -EINVAL; \ | ||
417 | WARN_ON(1); \ | ||
418 | } \ | ||
419 | } while (0) | ||
420 | AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), | ||
421 | "(%u vs %u)"); | ||
422 | AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); | ||
423 | AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ? | ||
424 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200, | ||
425 | "(%u vs %u)"); | ||
426 | AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)"); | ||
427 | AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)"); | ||
428 | AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)"); | ||
429 | AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); | ||
430 | #undef AIM_CHECK | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | #ifndef CONFIG_BUG | ||
435 | #define CONFIG_BUG 0 | ||
436 | #endif | ||
437 | |||
438 | /* | ||
439 | * Make sure there is an rpipe allocated for an endpoint | ||
440 | * | ||
441 | * If already allocated, we just refcount it; if not, we get an | ||
442 | * idle one, aim it to the right location and take it. | ||
443 | * | ||
444 | * Attaches to ep->hcpriv and rpipe->ep to ep. | ||
445 | */ | ||
446 | int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, | ||
447 | struct urb *urb, gfp_t gfp) | ||
448 | { | ||
449 | int result = 0; | ||
450 | struct device *dev = &wa->usb_iface->dev; | ||
451 | struct wa_rpipe *rpipe; | ||
452 | u8 eptype; | ||
453 | |||
454 | d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, | ||
455 | gfp); | ||
456 | mutex_lock(&wa->rpipe_mutex); | ||
457 | rpipe = ep->hcpriv; | ||
458 | if (rpipe != NULL) { | ||
459 | if (CONFIG_BUG == 1) { | ||
460 | result = rpipe_check_aim(rpipe, wa, ep, urb, gfp); | ||
461 | if (result < 0) | ||
462 | goto error; | ||
463 | } | ||
464 | __rpipe_get(rpipe); | ||
465 | d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n", | ||
466 | ep->desc.bEndpointAddress, | ||
467 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
468 | } else { | ||
469 | /* hmm, assign idle rpipe, aim it */ | ||
470 | result = -ENOBUFS; | ||
471 | eptype = ep->desc.bmAttributes & 0x03; | ||
472 | result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp); | ||
473 | if (result < 0) | ||
474 | goto error; | ||
475 | result = rpipe_aim(rpipe, wa, ep, urb, gfp); | ||
476 | if (result < 0) { | ||
477 | rpipe_put(rpipe); | ||
478 | goto error; | ||
479 | } | ||
480 | ep->hcpriv = rpipe; | ||
481 | rpipe->ep = ep; | ||
482 | __rpipe_get(rpipe); /* for caching into ep->hcpriv */ | ||
483 | d_printf(2, dev, "ep 0x%02x: using rpipe %u\n", | ||
484 | ep->desc.bEndpointAddress, | ||
485 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
486 | } | ||
487 | d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr)); | ||
488 | error: | ||
489 | mutex_unlock(&wa->rpipe_mutex); | ||
490 | d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp); | ||
491 | return result; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * Allocate the bitmap for each rpipe. | ||
496 | */ | ||
497 | int wa_rpipes_create(struct wahc *wa) | ||
498 | { | ||
499 | wa->rpipes = wa->wa_descr->wNumRPipes; | ||
500 | wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), | ||
501 | GFP_KERNEL); | ||
502 | if (wa->rpipe_bm == NULL) | ||
503 | return -ENOMEM; | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | void wa_rpipes_destroy(struct wahc *wa) | ||
508 | { | ||
509 | struct device *dev = &wa->usb_iface->dev; | ||
510 | d_fnstart(3, dev, "(wa %p)\n", wa); | ||
511 | if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { | ||
512 | char buf[256]; | ||
513 | WARN_ON(1); | ||
514 | bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes); | ||
515 | dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); | ||
516 | } | ||
517 | kfree(wa->rpipe_bm); | ||
518 | d_fnend(3, dev, "(wa %p)\n", wa); | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * Release resources allocated for an endpoint | ||
523 | * | ||
524 | * If there is an associated rpipe to this endpoint, Abort any pending | ||
525 | * transfers and put it. If the rpipe ends up being destroyed, | ||
526 | * __rpipe_destroy() will cleanup ep->hcpriv. | ||
527 | * | ||
528 | * This is called before calling hcd->stop(), so you don't need to do | ||
529 | * anything else in there. | ||
530 | */ | ||
531 | void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) | ||
532 | { | ||
533 | struct device *dev = &wa->usb_iface->dev; | ||
534 | struct wa_rpipe *rpipe; | ||
535 | d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
536 | mutex_lock(&wa->rpipe_mutex); | ||
537 | rpipe = ep->hcpriv; | ||
538 | if (rpipe != NULL) { | ||
539 | unsigned rc = atomic_read(&rpipe->refcnt.refcount); | ||
540 | int result; | ||
541 | u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
542 | |||
543 | if (rc != 1) | ||
544 | d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n", | ||
545 | wa, ep, rpipe, rc); | ||
546 | |||
547 | d_printf(1, dev, "rpipe %u: abort\n", index); | ||
548 | result = usb_control_msg( | ||
549 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
550 | USB_REQ_RPIPE_ABORT, | ||
551 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
552 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
553 | if (result < 0 && result != -ENODEV /* dev is gone */) | ||
554 | d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n", | ||
555 | wa, index, result); | ||
556 | rpipe_put(rpipe); | ||
557 | } | ||
558 | mutex_unlock(&wa->rpipe_mutex); | ||
559 | d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
560 | return; | ||
561 | } | ||
562 | EXPORT_SYMBOL_GPL(rpipe_ep_disable); | ||
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c new file mode 100644 index 000000000000..c038635d1c64 --- /dev/null +++ b/drivers/usb/wusbcore/wa-xfer.c | |||
@@ -0,0 +1,1709 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter | ||
3 | * Data transfer and URB enqueing | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * How transfers work: get a buffer, break it up in segments (segment | ||
24 | * size is a multiple of the maxpacket size). For each segment issue a | ||
25 | * segment request (struct wa_xfer_*), then send the data buffer if | ||
26 | * out or nothing if in (all over the DTO endpoint). | ||
27 | * | ||
28 | * For each submitted segment request, a notification will come over | ||
29 | * the NEP endpoint and a transfer result (struct xfer_result) will | ||
30 | * arrive in the DTI URB. Read it, get the xfer ID, see if there is | ||
31 | * data coming (inbound transfer), schedule a read and handle it. | ||
32 | * | ||
33 | * Sounds simple, it is a pain to implement. | ||
34 | * | ||
35 | * | ||
36 | * ENTRY POINTS | ||
37 | * | ||
38 | * FIXME | ||
39 | * | ||
40 | * LIFE CYCLE / STATE DIAGRAM | ||
41 | * | ||
42 | * FIXME | ||
43 | * | ||
44 | * THIS CODE IS DISGUSTING | ||
45 | * | ||
46 | * Warned you are; it's my second try and still not happy with it. | ||
47 | * | ||
48 | * NOTES: | ||
49 | * | ||
50 | * - No iso | ||
51 | * | ||
52 | * - Supports DMA xfers, control, bulk and maybe interrupt | ||
53 | * | ||
54 | * - Does not recycle unused rpipes | ||
55 | * | ||
56 | * An rpipe is assigned to an endpoint the first time it is used, | ||
57 | * and then it's there, assigned, until the endpoint is disabled | ||
58 | * (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the | ||
59 | * rpipe to the endpoint is done under the wa->rpipe_sem semaphore | ||
60 | * (should be a mutex). | ||
61 | * | ||
62 | * Two methods it could be done: | ||
63 | * | ||
64 | * (a) set up a timer everytime an rpipe's use count drops to 1 | ||
65 | * (which means unused) or when a transfer ends. Reset the | ||
66 | * timer when a xfer is queued. If the timer expires, release | ||
67 | * the rpipe [see rpipe_ep_disable()]. | ||
68 | * | ||
69 | * (b) when looking for free rpipes to attach [rpipe_get_by_ep()], | ||
70 | * when none are found go over the list, check their endpoint | ||
71 | * and their activity record (if no last-xfer-done-ts in the | ||
72 | * last x seconds) take it | ||
73 | * | ||
74 | * However, due to the fact that we have a set of limited | ||
75 | * resources (max-segments-at-the-same-time per xfer, | ||
76 | * xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end | ||
77 | * we are going to have to rebuild all this based on an scheduler, | ||
78 | * to where we have a list of transactions to do and based on the | ||
79 | * availability of the different requried components (blocks, | ||
80 | * rpipes, segment slots, etc), we go scheduling them. Painful. | ||
81 | */ | ||
82 | #include <linux/init.h> | ||
83 | #include <linux/spinlock.h> | ||
84 | #include <linux/hash.h> | ||
85 | #include "wa-hc.h" | ||
86 | #include "wusbhc.h" | ||
87 | |||
88 | #undef D_LOCAL | ||
89 | #define D_LOCAL 0 /* 0 disabled, > 0 different levels... */ | ||
90 | #include <linux/uwb/debug.h> | ||
91 | |||
92 | enum { | ||
93 | WA_SEGS_MAX = 255, | ||
94 | }; | ||
95 | |||
96 | enum wa_seg_status { | ||
97 | WA_SEG_NOTREADY, | ||
98 | WA_SEG_READY, | ||
99 | WA_SEG_DELAYED, | ||
100 | WA_SEG_SUBMITTED, | ||
101 | WA_SEG_PENDING, | ||
102 | WA_SEG_DTI_PENDING, | ||
103 | WA_SEG_DONE, | ||
104 | WA_SEG_ERROR, | ||
105 | WA_SEG_ABORTED, | ||
106 | }; | ||
107 | |||
108 | static void wa_xfer_delayed_run(struct wa_rpipe *); | ||
109 | |||
110 | /* | ||
111 | * Life cycle governed by 'struct urb' (the refcount of the struct is | ||
112 | * that of the 'struct urb' and usb_free_urb() would free the whole | ||
113 | * struct). | ||
114 | */ | ||
115 | struct wa_seg { | ||
116 | struct urb urb; | ||
117 | struct urb *dto_urb; /* for data output? */ | ||
118 | struct list_head list_node; /* for rpipe->req_list */ | ||
119 | struct wa_xfer *xfer; /* out xfer */ | ||
120 | u8 index; /* which segment we are */ | ||
121 | enum wa_seg_status status; | ||
122 | ssize_t result; /* bytes xfered or error */ | ||
123 | struct wa_xfer_hdr xfer_hdr; | ||
124 | u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */ | ||
125 | }; | ||
126 | |||
127 | static void wa_seg_init(struct wa_seg *seg) | ||
128 | { | ||
129 | /* usb_init_urb() repeats a lot of work, so we do it here */ | ||
130 | kref_init(&seg->urb.kref); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Protected by xfer->lock | ||
135 | * | ||
136 | */ | ||
137 | struct wa_xfer { | ||
138 | struct kref refcnt; | ||
139 | struct list_head list_node; | ||
140 | spinlock_t lock; | ||
141 | u32 id; | ||
142 | |||
143 | struct wahc *wa; /* Wire adapter we are plugged to */ | ||
144 | struct usb_host_endpoint *ep; | ||
145 | struct urb *urb; /* URB we are transfering for */ | ||
146 | struct wa_seg **seg; /* transfer segments */ | ||
147 | u8 segs, segs_submitted, segs_done; | ||
148 | unsigned is_inbound:1; | ||
149 | unsigned is_dma:1; | ||
150 | size_t seg_size; | ||
151 | int result; | ||
152 | |||
153 | gfp_t gfp; /* allocation mask */ | ||
154 | |||
155 | struct wusb_dev *wusb_dev; /* for activity timestamps */ | ||
156 | }; | ||
157 | |||
158 | static inline void wa_xfer_init(struct wa_xfer *xfer) | ||
159 | { | ||
160 | kref_init(&xfer->refcnt); | ||
161 | INIT_LIST_HEAD(&xfer->list_node); | ||
162 | spin_lock_init(&xfer->lock); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Destory a transfer structure | ||
167 | * | ||
168 | * Note that the xfer->seg[index] thingies follow the URB life cycle, | ||
169 | * so we need to put them, not free them. | ||
170 | */ | ||
171 | static void wa_xfer_destroy(struct kref *_xfer) | ||
172 | { | ||
173 | struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt); | ||
174 | if (xfer->seg) { | ||
175 | unsigned cnt; | ||
176 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
177 | if (xfer->is_inbound) | ||
178 | usb_put_urb(xfer->seg[cnt]->dto_urb); | ||
179 | usb_put_urb(&xfer->seg[cnt]->urb); | ||
180 | } | ||
181 | } | ||
182 | kfree(xfer); | ||
183 | d_printf(2, NULL, "xfer %p destroyed\n", xfer); | ||
184 | } | ||
185 | |||
186 | static void wa_xfer_get(struct wa_xfer *xfer) | ||
187 | { | ||
188 | kref_get(&xfer->refcnt); | ||
189 | } | ||
190 | |||
191 | static void wa_xfer_put(struct wa_xfer *xfer) | ||
192 | { | ||
193 | d_fnstart(3, NULL, "(xfer %p) -- ref count bef put %d\n", | ||
194 | xfer, atomic_read(&xfer->refcnt.refcount)); | ||
195 | kref_put(&xfer->refcnt, wa_xfer_destroy); | ||
196 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * xfer is referenced | ||
201 | * | ||
202 | * xfer->lock has to be unlocked | ||
203 | * | ||
204 | * We take xfer->lock for setting the result; this is a barrier | ||
205 | * against drivers/usb/core/hcd.c:unlink1() being called after we call | ||
206 | * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a | ||
207 | * reference to the transfer. | ||
208 | */ | ||
209 | static void wa_xfer_giveback(struct wa_xfer *xfer) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
213 | spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags); | ||
214 | list_del_init(&xfer->list_node); | ||
215 | spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags); | ||
216 | /* FIXME: segmentation broken -- kills DWA */ | ||
217 | wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result); | ||
218 | wa_put(xfer->wa); | ||
219 | wa_xfer_put(xfer); | ||
220 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * xfer is referenced | ||
225 | * | ||
226 | * xfer->lock has to be unlocked | ||
227 | */ | ||
228 | static void wa_xfer_completion(struct wa_xfer *xfer) | ||
229 | { | ||
230 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
231 | if (xfer->wusb_dev) | ||
232 | wusb_dev_put(xfer->wusb_dev); | ||
233 | rpipe_put(xfer->ep->hcpriv); | ||
234 | wa_xfer_giveback(xfer); | ||
235 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * If transfer is done, wrap it up and return true | ||
241 | * | ||
242 | * xfer->lock has to be locked | ||
243 | */ | ||
244 | static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) | ||
245 | { | ||
246 | unsigned result, cnt; | ||
247 | struct wa_seg *seg; | ||
248 | struct urb *urb = xfer->urb; | ||
249 | unsigned found_short = 0; | ||
250 | |||
251 | d_fnstart(3, NULL, "(xfer %p)\n", xfer); | ||
252 | result = xfer->segs_done == xfer->segs_submitted; | ||
253 | if (result == 0) | ||
254 | goto out; | ||
255 | urb->actual_length = 0; | ||
256 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
257 | seg = xfer->seg[cnt]; | ||
258 | switch (seg->status) { | ||
259 | case WA_SEG_DONE: | ||
260 | if (found_short && seg->result > 0) { | ||
261 | if (printk_ratelimit()) | ||
262 | printk(KERN_ERR "xfer %p#%u: bad short " | ||
263 | "segments (%zu)\n", xfer, cnt, | ||
264 | seg->result); | ||
265 | urb->status = -EINVAL; | ||
266 | goto out; | ||
267 | } | ||
268 | urb->actual_length += seg->result; | ||
269 | if (seg->result < xfer->seg_size | ||
270 | && cnt != xfer->segs-1) | ||
271 | found_short = 1; | ||
272 | d_printf(2, NULL, "xfer %p#%u: DONE short %d " | ||
273 | "result %zu urb->actual_length %d\n", | ||
274 | xfer, seg->index, found_short, seg->result, | ||
275 | urb->actual_length); | ||
276 | break; | ||
277 | case WA_SEG_ERROR: | ||
278 | xfer->result = seg->result; | ||
279 | d_printf(2, NULL, "xfer %p#%u: ERROR result %zu\n", | ||
280 | xfer, seg->index, seg->result); | ||
281 | goto out; | ||
282 | case WA_SEG_ABORTED: | ||
283 | WARN_ON(urb->status != -ECONNRESET | ||
284 | && urb->status != -ENOENT); | ||
285 | d_printf(2, NULL, "xfer %p#%u ABORTED: result %d\n", | ||
286 | xfer, seg->index, urb->status); | ||
287 | xfer->result = urb->status; | ||
288 | goto out; | ||
289 | default: | ||
290 | /* if (printk_ratelimit()) */ | ||
291 | printk(KERN_ERR "xfer %p#%u: " | ||
292 | "is_done bad state %d\n", | ||
293 | xfer, cnt, seg->status); | ||
294 | xfer->result = -EINVAL; | ||
295 | WARN_ON(1); | ||
296 | goto out; | ||
297 | } | ||
298 | } | ||
299 | xfer->result = 0; | ||
300 | out: | ||
301 | d_fnend(3, NULL, "(xfer %p) = void\n", xfer); | ||
302 | return result; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Initialize a transfer's ID | ||
307 | * | ||
308 | * We need to use a sequential number; if we use the pointer or the | ||
309 | * hash of the pointer, it can repeat over sequential transfers and | ||
310 | * then it will confuse the HWA....wonder why in hell they put a 32 | ||
311 | * bit handle in there then. | ||
312 | */ | ||
313 | static void wa_xfer_id_init(struct wa_xfer *xfer) | ||
314 | { | ||
315 | xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Return the xfer's ID associated with xfer | ||
320 | * | ||
321 | * Need to generate a | ||
322 | */ | ||
323 | static u32 wa_xfer_id(struct wa_xfer *xfer) | ||
324 | { | ||
325 | return xfer->id; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Search for a transfer list ID on the HCD's URB list | ||
330 | * | ||
331 | * For 32 bit architectures, we use the pointer itself; for 64 bits, a | ||
332 | * 32-bit hash of the pointer. | ||
333 | * | ||
334 | * @returns NULL if not found. | ||
335 | */ | ||
336 | static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id) | ||
337 | { | ||
338 | unsigned long flags; | ||
339 | struct wa_xfer *xfer_itr; | ||
340 | spin_lock_irqsave(&wa->xfer_list_lock, flags); | ||
341 | list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) { | ||
342 | if (id == xfer_itr->id) { | ||
343 | wa_xfer_get(xfer_itr); | ||
344 | goto out; | ||
345 | } | ||
346 | } | ||
347 | xfer_itr = NULL; | ||
348 | out: | ||
349 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags); | ||
350 | return xfer_itr; | ||
351 | } | ||
352 | |||
353 | struct wa_xfer_abort_buffer { | ||
354 | struct urb urb; | ||
355 | struct wa_xfer_abort cmd; | ||
356 | }; | ||
357 | |||
358 | static void __wa_xfer_abort_cb(struct urb *urb) | ||
359 | { | ||
360 | struct wa_xfer_abort_buffer *b = urb->context; | ||
361 | usb_put_urb(&b->urb); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Aborts an ongoing transaction | ||
366 | * | ||
367 | * Assumes the transfer is referenced and locked and in a submitted | ||
368 | * state (mainly that there is an endpoint/rpipe assigned). | ||
369 | * | ||
370 | * The callback (see above) does nothing but freeing up the data by | ||
371 | * putting the URB. Because the URB is allocated at the head of the | ||
372 | * struct, the whole space we allocated is kfreed. | ||
373 | * | ||
374 | * We'll get an 'aborted transaction' xfer result on DTI, that'll | ||
375 | * politely ignore because at this point the transaction has been | ||
376 | * marked as aborted already. | ||
377 | */ | ||
378 | static void __wa_xfer_abort(struct wa_xfer *xfer) | ||
379 | { | ||
380 | int result; | ||
381 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
382 | struct wa_xfer_abort_buffer *b; | ||
383 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
384 | |||
385 | b = kmalloc(sizeof(*b), GFP_ATOMIC); | ||
386 | if (b == NULL) | ||
387 | goto error_kmalloc; | ||
388 | b->cmd.bLength = sizeof(b->cmd); | ||
389 | b->cmd.bRequestType = WA_XFER_ABORT; | ||
390 | b->cmd.wRPipe = rpipe->descr.wRPipeIndex; | ||
391 | b->cmd.dwTransferID = wa_xfer_id(xfer); | ||
392 | |||
393 | usb_init_urb(&b->urb); | ||
394 | usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev, | ||
395 | usb_sndbulkpipe(xfer->wa->usb_dev, | ||
396 | xfer->wa->dto_epd->bEndpointAddress), | ||
397 | &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b); | ||
398 | result = usb_submit_urb(&b->urb, GFP_ATOMIC); | ||
399 | if (result < 0) | ||
400 | goto error_submit; | ||
401 | return; /* callback frees! */ | ||
402 | |||
403 | |||
404 | error_submit: | ||
405 | if (printk_ratelimit()) | ||
406 | dev_err(dev, "xfer %p: Can't submit abort request: %d\n", | ||
407 | xfer, result); | ||
408 | kfree(b); | ||
409 | error_kmalloc: | ||
410 | return; | ||
411 | |||
412 | } | ||
413 | |||
414 | /* | ||
415 | * | ||
416 | * @returns < 0 on error, transfer segment request size if ok | ||
417 | */ | ||
418 | static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer, | ||
419 | enum wa_xfer_type *pxfer_type) | ||
420 | { | ||
421 | ssize_t result; | ||
422 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
423 | size_t maxpktsize; | ||
424 | struct urb *urb = xfer->urb; | ||
425 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
426 | |||
427 | d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", | ||
428 | xfer, rpipe, urb); | ||
429 | switch (rpipe->descr.bmAttribute & 0x3) { | ||
430 | case USB_ENDPOINT_XFER_CONTROL: | ||
431 | *pxfer_type = WA_XFER_TYPE_CTL; | ||
432 | result = sizeof(struct wa_xfer_ctl); | ||
433 | break; | ||
434 | case USB_ENDPOINT_XFER_INT: | ||
435 | case USB_ENDPOINT_XFER_BULK: | ||
436 | *pxfer_type = WA_XFER_TYPE_BI; | ||
437 | result = sizeof(struct wa_xfer_bi); | ||
438 | break; | ||
439 | case USB_ENDPOINT_XFER_ISOC: | ||
440 | dev_err(dev, "FIXME: ISOC not implemented\n"); | ||
441 | result = -ENOSYS; | ||
442 | goto error; | ||
443 | default: | ||
444 | /* never happens */ | ||
445 | BUG(); | ||
446 | result = -EINVAL; /* shut gcc up */ | ||
447 | }; | ||
448 | xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0; | ||
449 | xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0; | ||
450 | xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks) | ||
451 | * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1); | ||
452 | /* Compute the segment size and make sure it is a multiple of | ||
453 | * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of | ||
454 | * a check (FIXME) */ | ||
455 | maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize); | ||
456 | if (xfer->seg_size < maxpktsize) { | ||
457 | dev_err(dev, "HW BUG? seg_size %zu smaller than maxpktsize " | ||
458 | "%zu\n", xfer->seg_size, maxpktsize); | ||
459 | result = -EINVAL; | ||
460 | goto error; | ||
461 | } | ||
462 | xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize; | ||
463 | xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1) | ||
464 | / xfer->seg_size; | ||
465 | if (xfer->segs >= WA_SEGS_MAX) { | ||
466 | dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n", | ||
467 | (int)(urb->transfer_buffer_length / xfer->seg_size), | ||
468 | WA_SEGS_MAX); | ||
469 | result = -EINVAL; | ||
470 | goto error; | ||
471 | } | ||
472 | if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) | ||
473 | xfer->segs = 1; | ||
474 | error: | ||
475 | d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", | ||
476 | xfer, rpipe, urb, (int)result); | ||
477 | return result; | ||
478 | } | ||
479 | |||
480 | /** Fill in the common request header and xfer-type specific data. */ | ||
481 | static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer, | ||
482 | struct wa_xfer_hdr *xfer_hdr0, | ||
483 | enum wa_xfer_type xfer_type, | ||
484 | size_t xfer_hdr_size) | ||
485 | { | ||
486 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
487 | |||
488 | xfer_hdr0 = &xfer->seg[0]->xfer_hdr; | ||
489 | xfer_hdr0->bLength = xfer_hdr_size; | ||
490 | xfer_hdr0->bRequestType = xfer_type; | ||
491 | xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex; | ||
492 | xfer_hdr0->dwTransferID = wa_xfer_id(xfer); | ||
493 | xfer_hdr0->bTransferSegment = 0; | ||
494 | switch (xfer_type) { | ||
495 | case WA_XFER_TYPE_CTL: { | ||
496 | struct wa_xfer_ctl *xfer_ctl = | ||
497 | container_of(xfer_hdr0, struct wa_xfer_ctl, hdr); | ||
498 | xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0; | ||
499 | BUG_ON(xfer->urb->transfer_flags & URB_NO_SETUP_DMA_MAP | ||
500 | && xfer->urb->setup_packet == NULL); | ||
501 | memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet, | ||
502 | sizeof(xfer_ctl->baSetupData)); | ||
503 | break; | ||
504 | } | ||
505 | case WA_XFER_TYPE_BI: | ||
506 | break; | ||
507 | case WA_XFER_TYPE_ISO: | ||
508 | printk(KERN_ERR "FIXME: ISOC not implemented\n"); | ||
509 | default: | ||
510 | BUG(); | ||
511 | }; | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * Callback for the OUT data phase of the segment request | ||
516 | * | ||
517 | * Check wa_seg_cb(); most comments also apply here because this | ||
518 | * function does almost the same thing and they work closely | ||
519 | * together. | ||
520 | * | ||
521 | * If the seg request has failed but this DTO phase has suceeded, | ||
522 | * wa_seg_cb() has already failed the segment and moved the | ||
523 | * status to WA_SEG_ERROR, so this will go through 'case 0' and | ||
524 | * effectively do nothing. | ||
525 | */ | ||
526 | static void wa_seg_dto_cb(struct urb *urb) | ||
527 | { | ||
528 | struct wa_seg *seg = urb->context; | ||
529 | struct wa_xfer *xfer = seg->xfer; | ||
530 | struct wahc *wa; | ||
531 | struct device *dev; | ||
532 | struct wa_rpipe *rpipe; | ||
533 | unsigned long flags; | ||
534 | unsigned rpipe_ready = 0; | ||
535 | u8 done = 0; | ||
536 | |||
537 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
538 | switch (urb->status) { | ||
539 | case 0: | ||
540 | spin_lock_irqsave(&xfer->lock, flags); | ||
541 | wa = xfer->wa; | ||
542 | dev = &wa->usb_iface->dev; | ||
543 | d_printf(2, dev, "xfer %p#%u: data out done (%d bytes)\n", | ||
544 | xfer, seg->index, urb->actual_length); | ||
545 | if (seg->status < WA_SEG_PENDING) | ||
546 | seg->status = WA_SEG_PENDING; | ||
547 | seg->result = urb->actual_length; | ||
548 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
549 | break; | ||
550 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
551 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
552 | break; | ||
553 | default: /* Other errors ... */ | ||
554 | spin_lock_irqsave(&xfer->lock, flags); | ||
555 | wa = xfer->wa; | ||
556 | dev = &wa->usb_iface->dev; | ||
557 | rpipe = xfer->ep->hcpriv; | ||
558 | if (printk_ratelimit()) | ||
559 | dev_err(dev, "xfer %p#%u: data out error %d\n", | ||
560 | xfer, seg->index, urb->status); | ||
561 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
562 | EDC_ERROR_TIMEFRAME)){ | ||
563 | dev_err(dev, "DTO: URB max acceptable errors " | ||
564 | "exceeded, resetting device\n"); | ||
565 | wa_reset_all(wa); | ||
566 | } | ||
567 | if (seg->status != WA_SEG_ERROR) { | ||
568 | seg->status = WA_SEG_ERROR; | ||
569 | seg->result = urb->status; | ||
570 | xfer->segs_done++; | ||
571 | __wa_xfer_abort(xfer); | ||
572 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
573 | done = __wa_xfer_is_done(xfer); | ||
574 | } | ||
575 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
576 | if (done) | ||
577 | wa_xfer_completion(xfer); | ||
578 | if (rpipe_ready) | ||
579 | wa_xfer_delayed_run(rpipe); | ||
580 | } | ||
581 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
582 | } | ||
583 | |||
584 | /* | ||
585 | * Callback for the segment request | ||
586 | * | ||
587 | * If succesful transition state (unless already transitioned or | ||
588 | * outbound transfer); otherwise, take a note of the error, mark this | ||
589 | * segment done and try completion. | ||
590 | * | ||
591 | * Note we don't access until we are sure that the transfer hasn't | ||
592 | * been cancelled (ECONNRESET, ENOENT), which could mean that | ||
593 | * seg->xfer could be already gone. | ||
594 | * | ||
595 | * We have to check before setting the status to WA_SEG_PENDING | ||
596 | * because sometimes the xfer result callback arrives before this | ||
597 | * callback (geeeeeeze), so it might happen that we are already in | ||
598 | * another state. As well, we don't set it if the transfer is inbound, | ||
599 | * as in that case, wa_seg_dto_cb will do it when the OUT data phase | ||
600 | * finishes. | ||
601 | */ | ||
602 | static void wa_seg_cb(struct urb *urb) | ||
603 | { | ||
604 | struct wa_seg *seg = urb->context; | ||
605 | struct wa_xfer *xfer = seg->xfer; | ||
606 | struct wahc *wa; | ||
607 | struct device *dev; | ||
608 | struct wa_rpipe *rpipe; | ||
609 | unsigned long flags; | ||
610 | unsigned rpipe_ready; | ||
611 | u8 done = 0; | ||
612 | |||
613 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
614 | switch (urb->status) { | ||
615 | case 0: | ||
616 | spin_lock_irqsave(&xfer->lock, flags); | ||
617 | wa = xfer->wa; | ||
618 | dev = &wa->usb_iface->dev; | ||
619 | d_printf(2, dev, "xfer %p#%u: request done\n", | ||
620 | xfer, seg->index); | ||
621 | if (xfer->is_inbound && seg->status < WA_SEG_PENDING) | ||
622 | seg->status = WA_SEG_PENDING; | ||
623 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
624 | break; | ||
625 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
626 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
627 | break; | ||
628 | default: /* Other errors ... */ | ||
629 | spin_lock_irqsave(&xfer->lock, flags); | ||
630 | wa = xfer->wa; | ||
631 | dev = &wa->usb_iface->dev; | ||
632 | rpipe = xfer->ep->hcpriv; | ||
633 | if (printk_ratelimit()) | ||
634 | dev_err(dev, "xfer %p#%u: request error %d\n", | ||
635 | xfer, seg->index, urb->status); | ||
636 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
637 | EDC_ERROR_TIMEFRAME)){ | ||
638 | dev_err(dev, "DTO: URB max acceptable errors " | ||
639 | "exceeded, resetting device\n"); | ||
640 | wa_reset_all(wa); | ||
641 | } | ||
642 | usb_unlink_urb(seg->dto_urb); | ||
643 | seg->status = WA_SEG_ERROR; | ||
644 | seg->result = urb->status; | ||
645 | xfer->segs_done++; | ||
646 | __wa_xfer_abort(xfer); | ||
647 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
648 | done = __wa_xfer_is_done(xfer); | ||
649 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
650 | if (done) | ||
651 | wa_xfer_completion(xfer); | ||
652 | if (rpipe_ready) | ||
653 | wa_xfer_delayed_run(rpipe); | ||
654 | } | ||
655 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Allocate the segs array and initialize each of them | ||
660 | * | ||
661 | * The segments are freed by wa_xfer_destroy() when the xfer use count | ||
662 | * drops to zero; however, because each segment is given the same life | ||
663 | * cycle as the USB URB it contains, it is actually freed by | ||
664 | * usb_put_urb() on the contained USB URB (twisted, eh?). | ||
665 | */ | ||
666 | static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size) | ||
667 | { | ||
668 | int result, cnt; | ||
669 | size_t alloc_size = sizeof(*xfer->seg[0]) | ||
670 | - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size; | ||
671 | struct usb_device *usb_dev = xfer->wa->usb_dev; | ||
672 | const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd; | ||
673 | struct wa_seg *seg; | ||
674 | size_t buf_itr, buf_size, buf_itr_size; | ||
675 | |||
676 | result = -ENOMEM; | ||
677 | xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC); | ||
678 | if (xfer->seg == NULL) | ||
679 | goto error_segs_kzalloc; | ||
680 | buf_itr = 0; | ||
681 | buf_size = xfer->urb->transfer_buffer_length; | ||
682 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
683 | seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC); | ||
684 | if (seg == NULL) | ||
685 | goto error_seg_kzalloc; | ||
686 | wa_seg_init(seg); | ||
687 | seg->xfer = xfer; | ||
688 | seg->index = cnt; | ||
689 | usb_fill_bulk_urb(&seg->urb, usb_dev, | ||
690 | usb_sndbulkpipe(usb_dev, | ||
691 | dto_epd->bEndpointAddress), | ||
692 | &seg->xfer_hdr, xfer_hdr_size, | ||
693 | wa_seg_cb, seg); | ||
694 | buf_itr_size = buf_size > xfer->seg_size ? | ||
695 | xfer->seg_size : buf_size; | ||
696 | if (xfer->is_inbound == 0 && buf_size > 0) { | ||
697 | seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
698 | if (seg->dto_urb == NULL) | ||
699 | goto error_dto_alloc; | ||
700 | usb_fill_bulk_urb( | ||
701 | seg->dto_urb, usb_dev, | ||
702 | usb_sndbulkpipe(usb_dev, | ||
703 | dto_epd->bEndpointAddress), | ||
704 | NULL, 0, wa_seg_dto_cb, seg); | ||
705 | if (xfer->is_dma) { | ||
706 | seg->dto_urb->transfer_dma = | ||
707 | xfer->urb->transfer_dma + buf_itr; | ||
708 | seg->dto_urb->transfer_flags |= | ||
709 | URB_NO_TRANSFER_DMA_MAP; | ||
710 | } else | ||
711 | seg->dto_urb->transfer_buffer = | ||
712 | xfer->urb->transfer_buffer + buf_itr; | ||
713 | seg->dto_urb->transfer_buffer_length = buf_itr_size; | ||
714 | } | ||
715 | seg->status = WA_SEG_READY; | ||
716 | buf_itr += buf_itr_size; | ||
717 | buf_size -= buf_itr_size; | ||
718 | } | ||
719 | return 0; | ||
720 | |||
721 | error_dto_alloc: | ||
722 | kfree(xfer->seg[cnt]); | ||
723 | cnt--; | ||
724 | error_seg_kzalloc: | ||
725 | /* use the fact that cnt is left at were it failed */ | ||
726 | for (; cnt > 0; cnt--) { | ||
727 | if (xfer->is_inbound == 0) | ||
728 | kfree(xfer->seg[cnt]->dto_urb); | ||
729 | kfree(xfer->seg[cnt]); | ||
730 | } | ||
731 | error_segs_kzalloc: | ||
732 | return result; | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | * Allocates all the stuff needed to submit a transfer | ||
737 | * | ||
738 | * Breaks the whole data buffer in a list of segments, each one has a | ||
739 | * structure allocated to it and linked in xfer->seg[index] | ||
740 | * | ||
741 | * FIXME: merge setup_segs() and the last part of this function, no | ||
742 | * need to do two for loops when we could run everything in a | ||
743 | * single one | ||
744 | */ | ||
745 | static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb) | ||
746 | { | ||
747 | int result; | ||
748 | struct device *dev = &xfer->wa->usb_iface->dev; | ||
749 | enum wa_xfer_type xfer_type = 0; /* shut up GCC */ | ||
750 | size_t xfer_hdr_size, cnt, transfer_size; | ||
751 | struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr; | ||
752 | |||
753 | d_fnstart(3, dev, "(xfer %p [rpipe %p] urb %p)\n", | ||
754 | xfer, xfer->ep->hcpriv, urb); | ||
755 | |||
756 | result = __wa_xfer_setup_sizes(xfer, &xfer_type); | ||
757 | if (result < 0) | ||
758 | goto error_setup_sizes; | ||
759 | xfer_hdr_size = result; | ||
760 | result = __wa_xfer_setup_segs(xfer, xfer_hdr_size); | ||
761 | if (result < 0) { | ||
762 | dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n", | ||
763 | xfer, xfer->segs, result); | ||
764 | goto error_setup_segs; | ||
765 | } | ||
766 | /* Fill the first header */ | ||
767 | xfer_hdr0 = &xfer->seg[0]->xfer_hdr; | ||
768 | wa_xfer_id_init(xfer); | ||
769 | __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size); | ||
770 | |||
771 | /* Fill remainig headers */ | ||
772 | xfer_hdr = xfer_hdr0; | ||
773 | transfer_size = urb->transfer_buffer_length; | ||
774 | xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ? | ||
775 | xfer->seg_size : transfer_size; | ||
776 | transfer_size -= xfer->seg_size; | ||
777 | for (cnt = 1; cnt < xfer->segs; cnt++) { | ||
778 | xfer_hdr = &xfer->seg[cnt]->xfer_hdr; | ||
779 | memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); | ||
780 | xfer_hdr->bTransferSegment = cnt; | ||
781 | xfer_hdr->dwTransferLength = transfer_size > xfer->seg_size ? | ||
782 | cpu_to_le32(xfer->seg_size) | ||
783 | : cpu_to_le32(transfer_size); | ||
784 | xfer->seg[cnt]->status = WA_SEG_READY; | ||
785 | transfer_size -= xfer->seg_size; | ||
786 | } | ||
787 | xfer_hdr->bTransferSegment |= 0x80; /* this is the last segment */ | ||
788 | result = 0; | ||
789 | error_setup_segs: | ||
790 | error_setup_sizes: | ||
791 | d_fnend(3, dev, "(xfer %p [rpipe %p] urb %p) = %d\n", | ||
792 | xfer, xfer->ep->hcpriv, urb, result); | ||
793 | return result; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * | ||
798 | * | ||
799 | * rpipe->seg_lock is held! | ||
800 | */ | ||
801 | static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer, | ||
802 | struct wa_seg *seg) | ||
803 | { | ||
804 | int result; | ||
805 | result = usb_submit_urb(&seg->urb, GFP_ATOMIC); | ||
806 | if (result < 0) { | ||
807 | printk(KERN_ERR "xfer %p#%u: REQ submit failed: %d\n", | ||
808 | xfer, seg->index, result); | ||
809 | goto error_seg_submit; | ||
810 | } | ||
811 | if (seg->dto_urb) { | ||
812 | result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); | ||
813 | if (result < 0) { | ||
814 | printk(KERN_ERR "xfer %p#%u: DTO submit failed: %d\n", | ||
815 | xfer, seg->index, result); | ||
816 | goto error_dto_submit; | ||
817 | } | ||
818 | } | ||
819 | seg->status = WA_SEG_SUBMITTED; | ||
820 | rpipe_avail_dec(rpipe); | ||
821 | return 0; | ||
822 | |||
823 | error_dto_submit: | ||
824 | usb_unlink_urb(&seg->urb); | ||
825 | error_seg_submit: | ||
826 | seg->status = WA_SEG_ERROR; | ||
827 | seg->result = result; | ||
828 | return result; | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * Execute more queued request segments until the maximum concurrent allowed | ||
833 | * | ||
834 | * The ugly unlock/lock sequence on the error path is needed as the | ||
835 | * xfer->lock normally nests the seg_lock and not viceversa. | ||
836 | * | ||
837 | */ | ||
838 | static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) | ||
839 | { | ||
840 | int result; | ||
841 | struct device *dev = &rpipe->wa->usb_iface->dev; | ||
842 | struct wa_seg *seg; | ||
843 | struct wa_xfer *xfer; | ||
844 | unsigned long flags; | ||
845 | |||
846 | d_fnstart(1, dev, "(rpipe #%d) %d segments available\n", | ||
847 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
848 | atomic_read(&rpipe->segs_available)); | ||
849 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
850 | while (atomic_read(&rpipe->segs_available) > 0 | ||
851 | && !list_empty(&rpipe->seg_list)) { | ||
852 | seg = list_entry(rpipe->seg_list.next, struct wa_seg, | ||
853 | list_node); | ||
854 | list_del(&seg->list_node); | ||
855 | xfer = seg->xfer; | ||
856 | result = __wa_seg_submit(rpipe, xfer, seg); | ||
857 | d_printf(1, dev, "xfer %p#%u submitted from delayed " | ||
858 | "[%d segments available] %d\n", | ||
859 | xfer, seg->index, | ||
860 | atomic_read(&rpipe->segs_available), result); | ||
861 | if (unlikely(result < 0)) { | ||
862 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
863 | spin_lock_irqsave(&xfer->lock, flags); | ||
864 | __wa_xfer_abort(xfer); | ||
865 | xfer->segs_done++; | ||
866 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
867 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
868 | } | ||
869 | } | ||
870 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
871 | d_fnend(1, dev, "(rpipe #%d) = void, %d segments available\n", | ||
872 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
873 | atomic_read(&rpipe->segs_available)); | ||
874 | |||
875 | } | ||
876 | |||
877 | /* | ||
878 | * | ||
879 | * xfer->lock is taken | ||
880 | * | ||
881 | * On failure submitting we just stop submitting and return error; | ||
882 | * wa_urb_enqueue_b() will execute the completion path | ||
883 | */ | ||
884 | static int __wa_xfer_submit(struct wa_xfer *xfer) | ||
885 | { | ||
886 | int result; | ||
887 | struct wahc *wa = xfer->wa; | ||
888 | struct device *dev = &wa->usb_iface->dev; | ||
889 | unsigned cnt; | ||
890 | struct wa_seg *seg; | ||
891 | unsigned long flags; | ||
892 | struct wa_rpipe *rpipe = xfer->ep->hcpriv; | ||
893 | size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests); | ||
894 | u8 available; | ||
895 | u8 empty; | ||
896 | |||
897 | d_fnstart(3, dev, "(xfer %p [rpipe %p])\n", | ||
898 | xfer, xfer->ep->hcpriv); | ||
899 | |||
900 | spin_lock_irqsave(&wa->xfer_list_lock, flags); | ||
901 | list_add_tail(&xfer->list_node, &wa->xfer_list); | ||
902 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags); | ||
903 | |||
904 | BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests); | ||
905 | result = 0; | ||
906 | spin_lock_irqsave(&rpipe->seg_lock, flags); | ||
907 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
908 | available = atomic_read(&rpipe->segs_available); | ||
909 | empty = list_empty(&rpipe->seg_list); | ||
910 | seg = xfer->seg[cnt]; | ||
911 | d_printf(2, dev, "xfer %p#%u: available %u empty %u (%s)\n", | ||
912 | xfer, cnt, available, empty, | ||
913 | available == 0 || !empty ? "delayed" : "submitted"); | ||
914 | if (available == 0 || !empty) { | ||
915 | d_printf(1, dev, "xfer %p#%u: delayed\n", xfer, cnt); | ||
916 | seg->status = WA_SEG_DELAYED; | ||
917 | list_add_tail(&seg->list_node, &rpipe->seg_list); | ||
918 | } else { | ||
919 | result = __wa_seg_submit(rpipe, xfer, seg); | ||
920 | if (result < 0) | ||
921 | goto error_seg_submit; | ||
922 | } | ||
923 | xfer->segs_submitted++; | ||
924 | } | ||
925 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
926 | d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, | ||
927 | xfer->ep->hcpriv); | ||
928 | return result; | ||
929 | |||
930 | error_seg_submit: | ||
931 | __wa_xfer_abort(xfer); | ||
932 | spin_unlock_irqrestore(&rpipe->seg_lock, flags); | ||
933 | d_fnend(3, dev, "(xfer %p [rpipe %p]) = void\n", xfer, | ||
934 | xfer->ep->hcpriv); | ||
935 | return result; | ||
936 | } | ||
937 | |||
938 | /* | ||
939 | * Second part of a URB/transfer enqueuement | ||
940 | * | ||
941 | * Assumes this comes from wa_urb_enqueue() [maybe through | ||
942 | * wa_urb_enqueue_run()]. At this point: | ||
943 | * | ||
944 | * xfer->wa filled and refcounted | ||
945 | * xfer->ep filled with rpipe refcounted if | ||
946 | * delayed == 0 | ||
947 | * xfer->urb filled and refcounted (this is the case when called | ||
948 | * from wa_urb_enqueue() as we come from usb_submit_urb() | ||
949 | * and when called by wa_urb_enqueue_run(), as we took an | ||
950 | * extra ref dropped by _run() after we return). | ||
951 | * xfer->gfp filled | ||
952 | * | ||
953 | * If we fail at __wa_xfer_submit(), then we just check if we are done | ||
954 | * and if so, we run the completion procedure. However, if we are not | ||
955 | * yet done, we do nothing and wait for the completion handlers from | ||
956 | * the submitted URBs or from the xfer-result path to kick in. If xfer | ||
957 | * result never kicks in, the xfer will timeout from the USB code and | ||
958 | * dequeue() will be called. | ||
959 | */ | ||
960 | static void wa_urb_enqueue_b(struct wa_xfer *xfer) | ||
961 | { | ||
962 | int result; | ||
963 | unsigned long flags; | ||
964 | struct urb *urb = xfer->urb; | ||
965 | struct wahc *wa = xfer->wa; | ||
966 | struct wusbhc *wusbhc = wa->wusb; | ||
967 | struct device *dev = &wa->usb_iface->dev; | ||
968 | struct wusb_dev *wusb_dev; | ||
969 | unsigned done; | ||
970 | |||
971 | d_fnstart(3, dev, "(wa %p urb %p)\n", wa, urb); | ||
972 | result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp); | ||
973 | if (result < 0) | ||
974 | goto error_rpipe_get; | ||
975 | result = -ENODEV; | ||
976 | /* FIXME: segmentation broken -- kills DWA */ | ||
977 | mutex_lock(&wusbhc->mutex); /* get a WUSB dev */ | ||
978 | if (urb->dev == NULL) | ||
979 | goto error_dev_gone; | ||
980 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); | ||
981 | if (wusb_dev == NULL) { | ||
982 | mutex_unlock(&wusbhc->mutex); | ||
983 | goto error_dev_gone; | ||
984 | } | ||
985 | mutex_unlock(&wusbhc->mutex); | ||
986 | |||
987 | spin_lock_irqsave(&xfer->lock, flags); | ||
988 | xfer->wusb_dev = wusb_dev; | ||
989 | result = urb->status; | ||
990 | if (urb->status != -EINPROGRESS) | ||
991 | goto error_dequeued; | ||
992 | |||
993 | result = __wa_xfer_setup(xfer, urb); | ||
994 | if (result < 0) | ||
995 | goto error_xfer_setup; | ||
996 | result = __wa_xfer_submit(xfer); | ||
997 | if (result < 0) | ||
998 | goto error_xfer_submit; | ||
999 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1000 | d_fnend(3, dev, "(wa %p urb %p) = void\n", wa, urb); | ||
1001 | return; | ||
1002 | |||
1003 | /* this is basically wa_xfer_completion() broken up wa_xfer_giveback() | ||
1004 | * does a wa_xfer_put() that will call wa_xfer_destroy() and clean | ||
1005 | * upundo setup(). | ||
1006 | */ | ||
1007 | error_xfer_setup: | ||
1008 | error_dequeued: | ||
1009 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1010 | /* FIXME: segmentation broken, kills DWA */ | ||
1011 | if (wusb_dev) | ||
1012 | wusb_dev_put(wusb_dev); | ||
1013 | error_dev_gone: | ||
1014 | rpipe_put(xfer->ep->hcpriv); | ||
1015 | error_rpipe_get: | ||
1016 | xfer->result = result; | ||
1017 | wa_xfer_giveback(xfer); | ||
1018 | d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); | ||
1019 | return; | ||
1020 | |||
1021 | error_xfer_submit: | ||
1022 | done = __wa_xfer_is_done(xfer); | ||
1023 | xfer->result = result; | ||
1024 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1025 | if (done) | ||
1026 | wa_xfer_completion(xfer); | ||
1027 | d_fnend(3, dev, "(wa %p urb %p) = (void) %d\n", wa, urb, result); | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * Execute the delayed transfers in the Wire Adapter @wa | ||
1033 | * | ||
1034 | * We need to be careful here, as dequeue() could be called in the | ||
1035 | * middle. That's why we do the whole thing under the | ||
1036 | * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock | ||
1037 | * and then checks the list -- so as we would be acquiring in inverse | ||
1038 | * order, we just drop the lock once we have the xfer and reacquire it | ||
1039 | * later. | ||
1040 | */ | ||
1041 | void wa_urb_enqueue_run(struct work_struct *ws) | ||
1042 | { | ||
1043 | struct wahc *wa = container_of(ws, struct wahc, xfer_work); | ||
1044 | struct device *dev = &wa->usb_iface->dev; | ||
1045 | struct wa_xfer *xfer, *next; | ||
1046 | struct urb *urb; | ||
1047 | |||
1048 | d_fnstart(3, dev, "(wa %p)\n", wa); | ||
1049 | spin_lock_irq(&wa->xfer_list_lock); | ||
1050 | list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list, | ||
1051 | list_node) { | ||
1052 | list_del_init(&xfer->list_node); | ||
1053 | spin_unlock_irq(&wa->xfer_list_lock); | ||
1054 | |||
1055 | urb = xfer->urb; | ||
1056 | wa_urb_enqueue_b(xfer); | ||
1057 | usb_put_urb(urb); /* taken when queuing */ | ||
1058 | |||
1059 | spin_lock_irq(&wa->xfer_list_lock); | ||
1060 | } | ||
1061 | spin_unlock_irq(&wa->xfer_list_lock); | ||
1062 | d_fnend(3, dev, "(wa %p) = void\n", wa); | ||
1063 | } | ||
1064 | EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); | ||
1065 | |||
1066 | /* | ||
1067 | * Submit a transfer to the Wire Adapter in a delayed way | ||
1068 | * | ||
1069 | * The process of enqueuing involves possible sleeps() [see | ||
1070 | * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are | ||
1071 | * in an atomic section, we defer the enqueue_b() call--else we call direct. | ||
1072 | * | ||
1073 | * @urb: We own a reference to it done by the HCI Linux USB stack that | ||
1074 | * will be given up by calling usb_hcd_giveback_urb() or by | ||
1075 | * returning error from this function -> ergo we don't have to | ||
1076 | * refcount it. | ||
1077 | */ | ||
1078 | int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, | ||
1079 | struct urb *urb, gfp_t gfp) | ||
1080 | { | ||
1081 | int result; | ||
1082 | struct device *dev = &wa->usb_iface->dev; | ||
1083 | struct wa_xfer *xfer; | ||
1084 | unsigned long my_flags; | ||
1085 | unsigned cant_sleep = irqs_disabled() | in_atomic(); | ||
1086 | |||
1087 | d_fnstart(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x)\n", | ||
1088 | wa, ep, urb, urb->transfer_buffer_length, gfp); | ||
1089 | |||
1090 | if (urb->transfer_buffer == NULL | ||
1091 | && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) | ||
1092 | && urb->transfer_buffer_length != 0) { | ||
1093 | dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb); | ||
1094 | dump_stack(); | ||
1095 | } | ||
1096 | |||
1097 | result = -ENOMEM; | ||
1098 | xfer = kzalloc(sizeof(*xfer), gfp); | ||
1099 | if (xfer == NULL) | ||
1100 | goto error_kmalloc; | ||
1101 | |||
1102 | result = -ENOENT; | ||
1103 | if (urb->status != -EINPROGRESS) /* cancelled */ | ||
1104 | goto error_dequeued; /* before starting? */ | ||
1105 | wa_xfer_init(xfer); | ||
1106 | xfer->wa = wa_get(wa); | ||
1107 | xfer->urb = urb; | ||
1108 | xfer->gfp = gfp; | ||
1109 | xfer->ep = ep; | ||
1110 | urb->hcpriv = xfer; | ||
1111 | d_printf(2, dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n", | ||
1112 | xfer, urb, urb->pipe, urb->transfer_buffer_length, | ||
1113 | urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma", | ||
1114 | urb->pipe & USB_DIR_IN ? "inbound" : "outbound", | ||
1115 | cant_sleep ? "deferred" : "inline"); | ||
1116 | if (cant_sleep) { | ||
1117 | usb_get_urb(urb); | ||
1118 | spin_lock_irqsave(&wa->xfer_list_lock, my_flags); | ||
1119 | list_add_tail(&xfer->list_node, &wa->xfer_delayed_list); | ||
1120 | spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); | ||
1121 | queue_work(wusbd, &wa->xfer_work); | ||
1122 | } else { | ||
1123 | wa_urb_enqueue_b(xfer); | ||
1124 | } | ||
1125 | d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = 0\n", | ||
1126 | wa, ep, urb, urb->transfer_buffer_length, gfp); | ||
1127 | return 0; | ||
1128 | |||
1129 | error_dequeued: | ||
1130 | kfree(xfer); | ||
1131 | error_kmalloc: | ||
1132 | d_fnend(3, dev, "(wa %p ep %p urb %p [%d] gfp 0x%x) = %d\n", | ||
1133 | wa, ep, urb, urb->transfer_buffer_length, gfp, result); | ||
1134 | return result; | ||
1135 | } | ||
1136 | EXPORT_SYMBOL_GPL(wa_urb_enqueue); | ||
1137 | |||
1138 | /* | ||
1139 | * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion | ||
1140 | * handler] is called. | ||
1141 | * | ||
1142 | * Until a transfer goes successfully through wa_urb_enqueue() it | ||
1143 | * needs to be dequeued with completion calling; when stuck in delayed | ||
1144 | * or before wa_xfer_setup() is called, we need to do completion. | ||
1145 | * | ||
1146 | * not setup If there is no hcpriv yet, that means that that enqueue | ||
1147 | * still had no time to set the xfer up. Because | ||
1148 | * urb->status should be other than -EINPROGRESS, | ||
1149 | * enqueue() will catch that and bail out. | ||
1150 | * | ||
1151 | * If the transfer has gone through setup, we just need to clean it | ||
1152 | * up. If it has gone through submit(), we have to abort it [with an | ||
1153 | * asynch request] and then make sure we cancel each segment. | ||
1154 | * | ||
1155 | */ | ||
1156 | int wa_urb_dequeue(struct wahc *wa, struct urb *urb) | ||
1157 | { | ||
1158 | struct device *dev = &wa->usb_iface->dev; | ||
1159 | unsigned long flags, flags2; | ||
1160 | struct wa_xfer *xfer; | ||
1161 | struct wa_seg *seg; | ||
1162 | struct wa_rpipe *rpipe; | ||
1163 | unsigned cnt; | ||
1164 | unsigned rpipe_ready = 0; | ||
1165 | |||
1166 | d_fnstart(3, dev, "(wa %p, urb %p)\n", wa, urb); | ||
1167 | |||
1168 | d_printf(1, dev, "xfer %p urb %p: aborting\n", urb->hcpriv, urb); | ||
1169 | xfer = urb->hcpriv; | ||
1170 | if (xfer == NULL) { | ||
1171 | /* NOthing setup yet enqueue will see urb->status != | ||
1172 | * -EINPROGRESS (by hcd layer) and bail out with | ||
1173 | * error, no need to do completion | ||
1174 | */ | ||
1175 | BUG_ON(urb->status == -EINPROGRESS); | ||
1176 | goto out; | ||
1177 | } | ||
1178 | spin_lock_irqsave(&xfer->lock, flags); | ||
1179 | rpipe = xfer->ep->hcpriv; | ||
1180 | /* Check the delayed list -> if there, release and complete */ | ||
1181 | spin_lock_irqsave(&wa->xfer_list_lock, flags2); | ||
1182 | if (!list_empty(&xfer->list_node) && xfer->seg == NULL) | ||
1183 | goto dequeue_delayed; | ||
1184 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); | ||
1185 | if (xfer->seg == NULL) /* still hasn't reached */ | ||
1186 | goto out_unlock; /* setup(), enqueue_b() completes */ | ||
1187 | /* Ok, the xfer is in flight already, it's been setup and submitted.*/ | ||
1188 | __wa_xfer_abort(xfer); | ||
1189 | for (cnt = 0; cnt < xfer->segs; cnt++) { | ||
1190 | seg = xfer->seg[cnt]; | ||
1191 | switch (seg->status) { | ||
1192 | case WA_SEG_NOTREADY: | ||
1193 | case WA_SEG_READY: | ||
1194 | printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n", | ||
1195 | xfer, cnt, seg->status); | ||
1196 | WARN_ON(1); | ||
1197 | break; | ||
1198 | case WA_SEG_DELAYED: | ||
1199 | seg->status = WA_SEG_ABORTED; | ||
1200 | spin_lock_irqsave(&rpipe->seg_lock, flags2); | ||
1201 | list_del(&seg->list_node); | ||
1202 | xfer->segs_done++; | ||
1203 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1204 | spin_unlock_irqrestore(&rpipe->seg_lock, flags2); | ||
1205 | break; | ||
1206 | case WA_SEG_SUBMITTED: | ||
1207 | seg->status = WA_SEG_ABORTED; | ||
1208 | usb_unlink_urb(&seg->urb); | ||
1209 | if (xfer->is_inbound == 0) | ||
1210 | usb_unlink_urb(seg->dto_urb); | ||
1211 | xfer->segs_done++; | ||
1212 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1213 | break; | ||
1214 | case WA_SEG_PENDING: | ||
1215 | seg->status = WA_SEG_ABORTED; | ||
1216 | xfer->segs_done++; | ||
1217 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1218 | break; | ||
1219 | case WA_SEG_DTI_PENDING: | ||
1220 | usb_unlink_urb(wa->dti_urb); | ||
1221 | seg->status = WA_SEG_ABORTED; | ||
1222 | xfer->segs_done++; | ||
1223 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1224 | break; | ||
1225 | case WA_SEG_DONE: | ||
1226 | case WA_SEG_ERROR: | ||
1227 | case WA_SEG_ABORTED: | ||
1228 | break; | ||
1229 | } | ||
1230 | } | ||
1231 | xfer->result = urb->status; /* -ENOENT or -ECONNRESET */ | ||
1232 | __wa_xfer_is_done(xfer); | ||
1233 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1234 | wa_xfer_completion(xfer); | ||
1235 | if (rpipe_ready) | ||
1236 | wa_xfer_delayed_run(rpipe); | ||
1237 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1238 | return 0; | ||
1239 | |||
1240 | out_unlock: | ||
1241 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1242 | out: | ||
1243 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1244 | return 0; | ||
1245 | |||
1246 | dequeue_delayed: | ||
1247 | list_del_init(&xfer->list_node); | ||
1248 | spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); | ||
1249 | xfer->result = urb->status; | ||
1250 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1251 | wa_xfer_giveback(xfer); | ||
1252 | usb_put_urb(urb); /* we got a ref in enqueue() */ | ||
1253 | d_fnend(3, dev, "(wa %p, urb %p) = 0\n", wa, urb); | ||
1254 | return 0; | ||
1255 | } | ||
1256 | EXPORT_SYMBOL_GPL(wa_urb_dequeue); | ||
1257 | |||
1258 | /* | ||
1259 | * Translation from WA status codes (WUSB1.0 Table 8.15) to errno | ||
1260 | * codes | ||
1261 | * | ||
1262 | * Positive errno values are internal inconsistencies and should be | ||
1263 | * flagged louder. Negative are to be passed up to the user in the | ||
1264 | * normal way. | ||
1265 | * | ||
1266 | * @status: USB WA status code -- high two bits are stripped. | ||
1267 | */ | ||
1268 | static int wa_xfer_status_to_errno(u8 status) | ||
1269 | { | ||
1270 | int errno; | ||
1271 | u8 real_status = status; | ||
1272 | static int xlat[] = { | ||
1273 | [WA_XFER_STATUS_SUCCESS] = 0, | ||
1274 | [WA_XFER_STATUS_HALTED] = -EPIPE, | ||
1275 | [WA_XFER_STATUS_DATA_BUFFER_ERROR] = -ENOBUFS, | ||
1276 | [WA_XFER_STATUS_BABBLE] = -EOVERFLOW, | ||
1277 | [WA_XFER_RESERVED] = EINVAL, | ||
1278 | [WA_XFER_STATUS_NOT_FOUND] = 0, | ||
1279 | [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM, | ||
1280 | [WA_XFER_STATUS_TRANSACTION_ERROR] = -EILSEQ, | ||
1281 | [WA_XFER_STATUS_ABORTED] = -EINTR, | ||
1282 | [WA_XFER_STATUS_RPIPE_NOT_READY] = EINVAL, | ||
1283 | [WA_XFER_INVALID_FORMAT] = EINVAL, | ||
1284 | [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = EINVAL, | ||
1285 | [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] = EINVAL, | ||
1286 | }; | ||
1287 | status &= 0x3f; | ||
1288 | |||
1289 | if (status == 0) | ||
1290 | return 0; | ||
1291 | if (status >= ARRAY_SIZE(xlat)) { | ||
1292 | if (printk_ratelimit()) | ||
1293 | printk(KERN_ERR "%s(): BUG? " | ||
1294 | "Unknown WA transfer status 0x%02x\n", | ||
1295 | __func__, real_status); | ||
1296 | return -EINVAL; | ||
1297 | } | ||
1298 | errno = xlat[status]; | ||
1299 | if (unlikely(errno > 0)) { | ||
1300 | if (printk_ratelimit()) | ||
1301 | printk(KERN_ERR "%s(): BUG? " | ||
1302 | "Inconsistent WA status: 0x%02x\n", | ||
1303 | __func__, real_status); | ||
1304 | errno = -errno; | ||
1305 | } | ||
1306 | return errno; | ||
1307 | } | ||
1308 | |||
1309 | /* | ||
1310 | * Process a xfer result completion message | ||
1311 | * | ||
1312 | * inbound transfers: need to schedule a DTI read | ||
1313 | * | ||
1314 | * FIXME: this functio needs to be broken up in parts | ||
1315 | */ | ||
1316 | static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) | ||
1317 | { | ||
1318 | int result; | ||
1319 | struct device *dev = &wa->usb_iface->dev; | ||
1320 | unsigned long flags; | ||
1321 | u8 seg_idx; | ||
1322 | struct wa_seg *seg; | ||
1323 | struct wa_rpipe *rpipe; | ||
1324 | struct wa_xfer_result *xfer_result = wa->xfer_result; | ||
1325 | u8 done = 0; | ||
1326 | u8 usb_status; | ||
1327 | unsigned rpipe_ready = 0; | ||
1328 | |||
1329 | d_fnstart(3, dev, "(wa %p xfer %p)\n", wa, xfer); | ||
1330 | spin_lock_irqsave(&xfer->lock, flags); | ||
1331 | seg_idx = xfer_result->bTransferSegment & 0x7f; | ||
1332 | if (unlikely(seg_idx >= xfer->segs)) | ||
1333 | goto error_bad_seg; | ||
1334 | seg = xfer->seg[seg_idx]; | ||
1335 | rpipe = xfer->ep->hcpriv; | ||
1336 | usb_status = xfer_result->bTransferStatus; | ||
1337 | d_printf(2, dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", | ||
1338 | xfer, seg_idx, usb_status, seg->status); | ||
1339 | if (seg->status == WA_SEG_ABORTED | ||
1340 | || seg->status == WA_SEG_ERROR) /* already handled */ | ||
1341 | goto segment_aborted; | ||
1342 | if (seg->status == WA_SEG_SUBMITTED) /* ops, got here */ | ||
1343 | seg->status = WA_SEG_PENDING; /* before wa_seg{_dto}_cb() */ | ||
1344 | if (seg->status != WA_SEG_PENDING) { | ||
1345 | if (printk_ratelimit()) | ||
1346 | dev_err(dev, "xfer %p#%u: Bad segment state %u\n", | ||
1347 | xfer, seg_idx, seg->status); | ||
1348 | seg->status = WA_SEG_PENDING; /* workaround/"fix" it */ | ||
1349 | } | ||
1350 | if (usb_status & 0x80) { | ||
1351 | seg->result = wa_xfer_status_to_errno(usb_status); | ||
1352 | dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n", | ||
1353 | xfer, seg->index, usb_status); | ||
1354 | goto error_complete; | ||
1355 | } | ||
1356 | /* FIXME: we ignore warnings, tally them for stats */ | ||
1357 | if (usb_status & 0x40) /* Warning?... */ | ||
1358 | usb_status = 0; /* ... pass */ | ||
1359 | if (xfer->is_inbound) { /* IN data phase: read to buffer */ | ||
1360 | seg->status = WA_SEG_DTI_PENDING; | ||
1361 | BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); | ||
1362 | if (xfer->is_dma) { | ||
1363 | wa->buf_in_urb->transfer_dma = | ||
1364 | xfer->urb->transfer_dma | ||
1365 | + seg_idx * xfer->seg_size; | ||
1366 | wa->buf_in_urb->transfer_flags | ||
1367 | |= URB_NO_TRANSFER_DMA_MAP; | ||
1368 | } else { | ||
1369 | wa->buf_in_urb->transfer_buffer = | ||
1370 | xfer->urb->transfer_buffer | ||
1371 | + seg_idx * xfer->seg_size; | ||
1372 | wa->buf_in_urb->transfer_flags | ||
1373 | &= ~URB_NO_TRANSFER_DMA_MAP; | ||
1374 | } | ||
1375 | wa->buf_in_urb->transfer_buffer_length = | ||
1376 | le32_to_cpu(xfer_result->dwTransferLength); | ||
1377 | wa->buf_in_urb->context = seg; | ||
1378 | result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); | ||
1379 | if (result < 0) | ||
1380 | goto error_submit_buf_in; | ||
1381 | } else { | ||
1382 | /* OUT data phase, complete it -- */ | ||
1383 | seg->status = WA_SEG_DONE; | ||
1384 | seg->result = le32_to_cpu(xfer_result->dwTransferLength); | ||
1385 | xfer->segs_done++; | ||
1386 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1387 | done = __wa_xfer_is_done(xfer); | ||
1388 | } | ||
1389 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1390 | if (done) | ||
1391 | wa_xfer_completion(xfer); | ||
1392 | if (rpipe_ready) | ||
1393 | wa_xfer_delayed_run(rpipe); | ||
1394 | d_fnend(3, dev, "(wa %p xfer %p) = void\n", wa, xfer); | ||
1395 | return; | ||
1396 | |||
1397 | |||
1398 | error_submit_buf_in: | ||
1399 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
1400 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1401 | "exceeded, resetting device\n"); | ||
1402 | wa_reset_all(wa); | ||
1403 | } | ||
1404 | if (printk_ratelimit()) | ||
1405 | dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n", | ||
1406 | xfer, seg_idx, result); | ||
1407 | seg->result = result; | ||
1408 | error_complete: | ||
1409 | seg->status = WA_SEG_ERROR; | ||
1410 | xfer->segs_done++; | ||
1411 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1412 | __wa_xfer_abort(xfer); | ||
1413 | done = __wa_xfer_is_done(xfer); | ||
1414 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1415 | if (done) | ||
1416 | wa_xfer_completion(xfer); | ||
1417 | if (rpipe_ready) | ||
1418 | wa_xfer_delayed_run(rpipe); | ||
1419 | d_fnend(3, dev, "(wa %p xfer %p) = void [segment/DTI-submit error]\n", | ||
1420 | wa, xfer); | ||
1421 | return; | ||
1422 | |||
1423 | |||
1424 | error_bad_seg: | ||
1425 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1426 | wa_urb_dequeue(wa, xfer->urb); | ||
1427 | if (printk_ratelimit()) | ||
1428 | dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx); | ||
1429 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { | ||
1430 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1431 | "exceeded, resetting device\n"); | ||
1432 | wa_reset_all(wa); | ||
1433 | } | ||
1434 | d_fnend(3, dev, "(wa %p xfer %p) = void [bad seg]\n", wa, xfer); | ||
1435 | return; | ||
1436 | |||
1437 | |||
1438 | segment_aborted: | ||
1439 | /* nothing to do, as the aborter did the completion */ | ||
1440 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1441 | d_fnend(3, dev, "(wa %p xfer %p) = void [segment aborted]\n", | ||
1442 | wa, xfer); | ||
1443 | return; | ||
1444 | |||
1445 | } | ||
1446 | |||
1447 | /* | ||
1448 | * Callback for the IN data phase | ||
1449 | * | ||
1450 | * If succesful transition state; otherwise, take a note of the | ||
1451 | * error, mark this segment done and try completion. | ||
1452 | * | ||
1453 | * Note we don't access until we are sure that the transfer hasn't | ||
1454 | * been cancelled (ECONNRESET, ENOENT), which could mean that | ||
1455 | * seg->xfer could be already gone. | ||
1456 | */ | ||
1457 | static void wa_buf_in_cb(struct urb *urb) | ||
1458 | { | ||
1459 | struct wa_seg *seg = urb->context; | ||
1460 | struct wa_xfer *xfer = seg->xfer; | ||
1461 | struct wahc *wa; | ||
1462 | struct device *dev; | ||
1463 | struct wa_rpipe *rpipe; | ||
1464 | unsigned rpipe_ready; | ||
1465 | unsigned long flags; | ||
1466 | u8 done = 0; | ||
1467 | |||
1468 | d_fnstart(3, NULL, "(urb %p [%d])\n", urb, urb->status); | ||
1469 | switch (urb->status) { | ||
1470 | case 0: | ||
1471 | spin_lock_irqsave(&xfer->lock, flags); | ||
1472 | wa = xfer->wa; | ||
1473 | dev = &wa->usb_iface->dev; | ||
1474 | rpipe = xfer->ep->hcpriv; | ||
1475 | d_printf(2, dev, "xfer %p#%u: data in done (%zu bytes)\n", | ||
1476 | xfer, seg->index, (size_t)urb->actual_length); | ||
1477 | seg->status = WA_SEG_DONE; | ||
1478 | seg->result = urb->actual_length; | ||
1479 | xfer->segs_done++; | ||
1480 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1481 | done = __wa_xfer_is_done(xfer); | ||
1482 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1483 | if (done) | ||
1484 | wa_xfer_completion(xfer); | ||
1485 | if (rpipe_ready) | ||
1486 | wa_xfer_delayed_run(rpipe); | ||
1487 | break; | ||
1488 | case -ECONNRESET: /* URB unlinked; no need to do anything */ | ||
1489 | case -ENOENT: /* as it was done by the who unlinked us */ | ||
1490 | break; | ||
1491 | default: /* Other errors ... */ | ||
1492 | spin_lock_irqsave(&xfer->lock, flags); | ||
1493 | wa = xfer->wa; | ||
1494 | dev = &wa->usb_iface->dev; | ||
1495 | rpipe = xfer->ep->hcpriv; | ||
1496 | if (printk_ratelimit()) | ||
1497 | dev_err(dev, "xfer %p#%u: data in error %d\n", | ||
1498 | xfer, seg->index, urb->status); | ||
1499 | if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, | ||
1500 | EDC_ERROR_TIMEFRAME)){ | ||
1501 | dev_err(dev, "DTO: URB max acceptable errors " | ||
1502 | "exceeded, resetting device\n"); | ||
1503 | wa_reset_all(wa); | ||
1504 | } | ||
1505 | seg->status = WA_SEG_ERROR; | ||
1506 | seg->result = urb->status; | ||
1507 | xfer->segs_done++; | ||
1508 | rpipe_ready = rpipe_avail_inc(rpipe); | ||
1509 | __wa_xfer_abort(xfer); | ||
1510 | done = __wa_xfer_is_done(xfer); | ||
1511 | spin_unlock_irqrestore(&xfer->lock, flags); | ||
1512 | if (done) | ||
1513 | wa_xfer_completion(xfer); | ||
1514 | if (rpipe_ready) | ||
1515 | wa_xfer_delayed_run(rpipe); | ||
1516 | } | ||
1517 | d_fnend(3, NULL, "(urb %p [%d]) = void\n", urb, urb->status); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Handle an incoming transfer result buffer | ||
1522 | * | ||
1523 | * Given a transfer result buffer, it completes the transfer (possibly | ||
1524 | * scheduling and buffer in read) and then resubmits the DTI URB for a | ||
1525 | * new transfer result read. | ||
1526 | * | ||
1527 | * | ||
1528 | * The xfer_result DTI URB state machine | ||
1529 | * | ||
1530 | * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In) | ||
1531 | * | ||
1532 | * We start in OFF mode, the first xfer_result notification [through | ||
1533 | * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to | ||
1534 | * read. | ||
1535 | * | ||
1536 | * We receive a buffer -- if it is not a xfer_result, we complain and | ||
1537 | * repost the DTI-URB. If it is a xfer_result then do the xfer seg | ||
1538 | * request accounting. If it is an IN segment, we move to RBI and post | ||
1539 | * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will | ||
1540 | * repost the DTI-URB and move to RXR state. if there was no IN | ||
1541 | * segment, it will repost the DTI-URB. | ||
1542 | * | ||
1543 | * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many | ||
1544 | * errors) in the URBs. | ||
1545 | */ | ||
1546 | static void wa_xfer_result_cb(struct urb *urb) | ||
1547 | { | ||
1548 | int result; | ||
1549 | struct wahc *wa = urb->context; | ||
1550 | struct device *dev = &wa->usb_iface->dev; | ||
1551 | struct wa_xfer_result *xfer_result; | ||
1552 | u32 xfer_id; | ||
1553 | struct wa_xfer *xfer; | ||
1554 | u8 usb_status; | ||
1555 | |||
1556 | d_fnstart(3, dev, "(%p)\n", wa); | ||
1557 | BUG_ON(wa->dti_urb != urb); | ||
1558 | switch (wa->dti_urb->status) { | ||
1559 | case 0: | ||
1560 | /* We have a xfer result buffer; check it */ | ||
1561 | d_printf(2, dev, "DTI: xfer result %d bytes at %p\n", | ||
1562 | urb->actual_length, urb->transfer_buffer); | ||
1563 | d_dump(3, dev, urb->transfer_buffer, urb->actual_length); | ||
1564 | if (wa->dti_urb->actual_length != sizeof(*xfer_result)) { | ||
1565 | dev_err(dev, "DTI Error: xfer result--bad size " | ||
1566 | "xfer result (%d bytes vs %zu needed)\n", | ||
1567 | urb->actual_length, sizeof(*xfer_result)); | ||
1568 | break; | ||
1569 | } | ||
1570 | xfer_result = wa->xfer_result; | ||
1571 | if (xfer_result->hdr.bLength != sizeof(*xfer_result)) { | ||
1572 | dev_err(dev, "DTI Error: xfer result--" | ||
1573 | "bad header length %u\n", | ||
1574 | xfer_result->hdr.bLength); | ||
1575 | break; | ||
1576 | } | ||
1577 | if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) { | ||
1578 | dev_err(dev, "DTI Error: xfer result--" | ||
1579 | "bad header type 0x%02x\n", | ||
1580 | xfer_result->hdr.bNotifyType); | ||
1581 | break; | ||
1582 | } | ||
1583 | usb_status = xfer_result->bTransferStatus & 0x3f; | ||
1584 | if (usb_status == WA_XFER_STATUS_ABORTED | ||
1585 | || usb_status == WA_XFER_STATUS_NOT_FOUND) | ||
1586 | /* taken care of already */ | ||
1587 | break; | ||
1588 | xfer_id = xfer_result->dwTransferID; | ||
1589 | xfer = wa_xfer_get_by_id(wa, xfer_id); | ||
1590 | if (xfer == NULL) { | ||
1591 | /* FIXME: transaction might have been cancelled */ | ||
1592 | dev_err(dev, "DTI Error: xfer result--" | ||
1593 | "unknown xfer 0x%08x (status 0x%02x)\n", | ||
1594 | xfer_id, usb_status); | ||
1595 | break; | ||
1596 | } | ||
1597 | wa_xfer_result_chew(wa, xfer); | ||
1598 | wa_xfer_put(xfer); | ||
1599 | break; | ||
1600 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
1601 | case -ESHUTDOWN: /* going away! */ | ||
1602 | dev_dbg(dev, "DTI: going down! %d\n", urb->status); | ||
1603 | goto out; | ||
1604 | default: | ||
1605 | /* Unknown error */ | ||
1606 | if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, | ||
1607 | EDC_ERROR_TIMEFRAME)) { | ||
1608 | dev_err(dev, "DTI: URB max acceptable errors " | ||
1609 | "exceeded, resetting device\n"); | ||
1610 | wa_reset_all(wa); | ||
1611 | goto out; | ||
1612 | } | ||
1613 | if (printk_ratelimit()) | ||
1614 | dev_err(dev, "DTI: URB error %d\n", urb->status); | ||
1615 | break; | ||
1616 | } | ||
1617 | /* Resubmit the DTI URB */ | ||
1618 | result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); | ||
1619 | if (result < 0) { | ||
1620 | dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " | ||
1621 | "resetting\n", result); | ||
1622 | wa_reset_all(wa); | ||
1623 | } | ||
1624 | out: | ||
1625 | d_fnend(3, dev, "(%p) = void\n", wa); | ||
1626 | return; | ||
1627 | } | ||
1628 | |||
1629 | /* | ||
1630 | * Transfer complete notification | ||
1631 | * | ||
1632 | * Called from the notif.c code. We get a notification on EP2 saying | ||
1633 | * that some endpoint has some transfer result data available. We are | ||
1634 | * about to read it. | ||
1635 | * | ||
1636 | * To speed up things, we always have a URB reading the DTI URB; we | ||
1637 | * don't really set it up and start it until the first xfer complete | ||
1638 | * notification arrives, which is what we do here. | ||
1639 | * | ||
1640 | * Follow up in wa_xfer_result_cb(), as that's where the whole state | ||
1641 | * machine starts. | ||
1642 | * | ||
1643 | * So here we just initialize the DTI URB for reading transfer result | ||
1644 | * notifications and also the buffer-in URB, for reading buffers. Then | ||
1645 | * we just submit the DTI URB. | ||
1646 | * | ||
1647 | * @wa shall be referenced | ||
1648 | */ | ||
1649 | void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) | ||
1650 | { | ||
1651 | int result; | ||
1652 | struct device *dev = &wa->usb_iface->dev; | ||
1653 | struct wa_notif_xfer *notif_xfer; | ||
1654 | const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; | ||
1655 | |||
1656 | d_fnstart(4, dev, "(%p, %p)\n", wa, notif_hdr); | ||
1657 | notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); | ||
1658 | BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); | ||
1659 | |||
1660 | if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) { | ||
1661 | /* FIXME: hardcoded limitation, adapt */ | ||
1662 | dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n", | ||
1663 | notif_xfer->bEndpoint, dti_epd->bEndpointAddress); | ||
1664 | goto error; | ||
1665 | } | ||
1666 | if (wa->dti_urb != NULL) /* DTI URB already started */ | ||
1667 | goto out; | ||
1668 | |||
1669 | wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1670 | if (wa->dti_urb == NULL) { | ||
1671 | dev_err(dev, "Can't allocate DTI URB\n"); | ||
1672 | goto error_dti_urb_alloc; | ||
1673 | } | ||
1674 | usb_fill_bulk_urb( | ||
1675 | wa->dti_urb, wa->usb_dev, | ||
1676 | usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), | ||
1677 | wa->xfer_result, wa->xfer_result_size, | ||
1678 | wa_xfer_result_cb, wa); | ||
1679 | |||
1680 | wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1681 | if (wa->buf_in_urb == NULL) { | ||
1682 | dev_err(dev, "Can't allocate BUF-IN URB\n"); | ||
1683 | goto error_buf_in_urb_alloc; | ||
1684 | } | ||
1685 | usb_fill_bulk_urb( | ||
1686 | wa->buf_in_urb, wa->usb_dev, | ||
1687 | usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), | ||
1688 | NULL, 0, wa_buf_in_cb, wa); | ||
1689 | result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); | ||
1690 | if (result < 0) { | ||
1691 | dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " | ||
1692 | "resetting\n", result); | ||
1693 | goto error_dti_urb_submit; | ||
1694 | } | ||
1695 | out: | ||
1696 | d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); | ||
1697 | return; | ||
1698 | |||
1699 | error_dti_urb_submit: | ||
1700 | usb_put_urb(wa->buf_in_urb); | ||
1701 | error_buf_in_urb_alloc: | ||
1702 | usb_put_urb(wa->dti_urb); | ||
1703 | wa->dti_urb = NULL; | ||
1704 | error_dti_urb_alloc: | ||
1705 | error: | ||
1706 | wa_reset_all(wa); | ||
1707 | d_fnend(4, dev, "(%p, %p) = void\n", wa, notif_hdr); | ||
1708 | return; | ||
1709 | } | ||
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c new file mode 100644 index 000000000000..07c63a31c799 --- /dev/null +++ b/drivers/usb/wusbcore/wusbhc.c | |||
@@ -0,0 +1,418 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * sysfs glue, wusbcore module support and life cycle management | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * Creation/destruction of wusbhc is split in two parts; that that | ||
25 | * doesn't require the HCD to be added (wusbhc_{create,destroy}) and | ||
26 | * the one that requires (phase B, wusbhc_b_{create,destroy}). | ||
27 | * | ||
28 | * This is so because usb_add_hcd() will start the HC, and thus, all | ||
29 | * the HC specific stuff has to be already initialiazed (like sysfs | ||
30 | * thingies). | ||
31 | */ | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/module.h> | ||
34 | #include "wusbhc.h" | ||
35 | |||
36 | /** | ||
37 | * Extract the wusbhc that corresponds to a USB Host Controller class device | ||
38 | * | ||
39 | * WARNING! Apply only if @dev is that of a | ||
40 | * wusbhc.usb_hcd.self->class_dev; otherwise, you loose. | ||
41 | */ | ||
42 | static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev) | ||
43 | { | ||
44 | struct usb_bus *usb_bus = dev_get_drvdata(dev); | ||
45 | struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus); | ||
46 | return usb_hcd_to_wusbhc(usb_hcd); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Show & store the current WUSB trust timeout | ||
51 | * | ||
52 | * We don't do locking--it is an 'atomic' value. | ||
53 | * | ||
54 | * The units that we store/show are always MILLISECONDS. However, the | ||
55 | * value of trust_timeout is jiffies. | ||
56 | */ | ||
57 | static ssize_t wusb_trust_timeout_show(struct device *dev, | ||
58 | struct device_attribute *attr, char *buf) | ||
59 | { | ||
60 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
61 | |||
62 | return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout); | ||
63 | } | ||
64 | |||
65 | static ssize_t wusb_trust_timeout_store(struct device *dev, | ||
66 | struct device_attribute *attr, | ||
67 | const char *buf, size_t size) | ||
68 | { | ||
69 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
70 | ssize_t result = -ENOSYS; | ||
71 | unsigned trust_timeout; | ||
72 | |||
73 | result = sscanf(buf, "%u", &trust_timeout); | ||
74 | if (result != 1) { | ||
75 | result = -EINVAL; | ||
76 | goto out; | ||
77 | } | ||
78 | /* FIXME: maybe we should check for range validity? */ | ||
79 | wusbhc->trust_timeout = trust_timeout; | ||
80 | cancel_delayed_work(&wusbhc->keep_alive_timer); | ||
81 | flush_workqueue(wusbd); | ||
82 | queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, | ||
83 | (trust_timeout * CONFIG_HZ)/1000/2); | ||
84 | out: | ||
85 | return result < 0 ? result : size; | ||
86 | } | ||
87 | static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show, | ||
88 | wusb_trust_timeout_store); | ||
89 | |||
90 | /* | ||
91 | * Show & store the current WUSB CHID | ||
92 | */ | ||
93 | static ssize_t wusb_chid_show(struct device *dev, | ||
94 | struct device_attribute *attr, char *buf) | ||
95 | { | ||
96 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
97 | ssize_t result = 0; | ||
98 | |||
99 | if (wusbhc->wuie_host_info != NULL) | ||
100 | result += ckhdid_printf(buf, PAGE_SIZE, | ||
101 | &wusbhc->wuie_host_info->CHID); | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Store a new CHID | ||
107 | * | ||
108 | * This will (FIXME) trigger many changes. | ||
109 | * | ||
110 | * - Send an all zeros CHID and it will stop the controller | ||
111 | * - Send a non-zero CHID and it will start it | ||
112 | * (unless it was started, it will just change the CHID, | ||
113 | * diconnecting all devices first). | ||
114 | * | ||
115 | * So first we scan the MMC we are sent and then we act on it. We | ||
116 | * read it in the same format as we print it, an ASCII string of 16 | ||
117 | * hex bytes. | ||
118 | * | ||
119 | * See wusbhc_chid_set() for more info. | ||
120 | */ | ||
121 | static ssize_t wusb_chid_store(struct device *dev, | ||
122 | struct device_attribute *attr, | ||
123 | const char *buf, size_t size) | ||
124 | { | ||
125 | struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); | ||
126 | struct wusb_ckhdid chid; | ||
127 | ssize_t result; | ||
128 | |||
129 | result = sscanf(buf, | ||
130 | "%02hhx %02hhx %02hhx %02hhx " | ||
131 | "%02hhx %02hhx %02hhx %02hhx " | ||
132 | "%02hhx %02hhx %02hhx %02hhx " | ||
133 | "%02hhx %02hhx %02hhx %02hhx\n", | ||
134 | &chid.data[0] , &chid.data[1] , | ||
135 | &chid.data[2] , &chid.data[3] , | ||
136 | &chid.data[4] , &chid.data[5] , | ||
137 | &chid.data[6] , &chid.data[7] , | ||
138 | &chid.data[8] , &chid.data[9] , | ||
139 | &chid.data[10], &chid.data[11], | ||
140 | &chid.data[12], &chid.data[13], | ||
141 | &chid.data[14], &chid.data[15]); | ||
142 | if (result != 16) { | ||
143 | dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): " | ||
144 | "%d\n", (int)result); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | result = wusbhc_chid_set(wusbhc, &chid); | ||
148 | return result < 0 ? result : size; | ||
149 | } | ||
150 | static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store); | ||
151 | |||
152 | /* Group all the WUSBHC attributes */ | ||
153 | static struct attribute *wusbhc_attrs[] = { | ||
154 | &dev_attr_wusb_trust_timeout.attr, | ||
155 | &dev_attr_wusb_chid.attr, | ||
156 | NULL, | ||
157 | }; | ||
158 | |||
159 | static struct attribute_group wusbhc_attr_group = { | ||
160 | .name = NULL, /* we want them in the same directory */ | ||
161 | .attrs = wusbhc_attrs, | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * Create a wusbhc instance | ||
166 | * | ||
167 | * NOTEs: | ||
168 | * | ||
169 | * - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been | ||
170 | * initialized but not added. | ||
171 | * | ||
172 | * - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling. | ||
173 | * | ||
174 | * - fill out wusbhc->uwb_rc and refcount it before calling | ||
175 | * - fill out the wusbhc->sec_modes array | ||
176 | */ | ||
177 | int wusbhc_create(struct wusbhc *wusbhc) | ||
178 | { | ||
179 | int result = 0; | ||
180 | |||
181 | wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS; | ||
182 | mutex_init(&wusbhc->mutex); | ||
183 | result = wusbhc_mmcie_create(wusbhc); | ||
184 | if (result < 0) | ||
185 | goto error_mmcie_create; | ||
186 | result = wusbhc_devconnect_create(wusbhc); | ||
187 | if (result < 0) | ||
188 | goto error_devconnect_create; | ||
189 | result = wusbhc_rh_create(wusbhc); | ||
190 | if (result < 0) | ||
191 | goto error_rh_create; | ||
192 | result = wusbhc_sec_create(wusbhc); | ||
193 | if (result < 0) | ||
194 | goto error_sec_create; | ||
195 | return 0; | ||
196 | |||
197 | error_sec_create: | ||
198 | wusbhc_rh_destroy(wusbhc); | ||
199 | error_rh_create: | ||
200 | wusbhc_devconnect_destroy(wusbhc); | ||
201 | error_devconnect_create: | ||
202 | wusbhc_mmcie_destroy(wusbhc); | ||
203 | error_mmcie_create: | ||
204 | return result; | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(wusbhc_create); | ||
207 | |||
208 | static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc) | ||
209 | { | ||
210 | return &wusbhc->usb_hcd.self.controller->kobj; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Phase B of a wusbhc instance creation | ||
215 | * | ||
216 | * Creates fields that depend on wusbhc->usb_hcd having been | ||
217 | * added. This is where we create the sysfs files in | ||
218 | * /sys/class/usb_host/usb_hostX/. | ||
219 | * | ||
220 | * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper | ||
221 | * layer (hwahc or whci) | ||
222 | */ | ||
223 | int wusbhc_b_create(struct wusbhc *wusbhc) | ||
224 | { | ||
225 | int result = 0; | ||
226 | struct device *dev = wusbhc->usb_hcd.self.controller; | ||
227 | |||
228 | result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
229 | if (result < 0) { | ||
230 | dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result); | ||
231 | goto error_create_attr_group; | ||
232 | } | ||
233 | |||
234 | result = wusbhc_pal_register(wusbhc); | ||
235 | if (result < 0) | ||
236 | goto error_pal_register; | ||
237 | return 0; | ||
238 | |||
239 | error_pal_register: | ||
240 | sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
241 | error_create_attr_group: | ||
242 | return result; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(wusbhc_b_create); | ||
245 | |||
246 | void wusbhc_b_destroy(struct wusbhc *wusbhc) | ||
247 | { | ||
248 | wusbhc_pal_unregister(wusbhc); | ||
249 | sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(wusbhc_b_destroy); | ||
252 | |||
253 | void wusbhc_destroy(struct wusbhc *wusbhc) | ||
254 | { | ||
255 | wusbhc_sec_destroy(wusbhc); | ||
256 | wusbhc_rh_destroy(wusbhc); | ||
257 | wusbhc_devconnect_destroy(wusbhc); | ||
258 | wusbhc_mmcie_destroy(wusbhc); | ||
259 | } | ||
260 | EXPORT_SYMBOL_GPL(wusbhc_destroy); | ||
261 | |||
262 | struct workqueue_struct *wusbd; | ||
263 | EXPORT_SYMBOL_GPL(wusbd); | ||
264 | |||
265 | /* | ||
266 | * WUSB Cluster ID allocation map | ||
267 | * | ||
268 | * Each WUSB bus in a channel is identified with a Cluster Id in the | ||
269 | * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff | ||
270 | * (that's space for 31 WUSB controllers, as 0xff can't be taken). We | ||
271 | * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff). | ||
272 | * | ||
273 | * For each one we taken, we pin it in the bitap | ||
274 | */ | ||
275 | #define CLUSTER_IDS 32 | ||
276 | static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS); | ||
277 | static DEFINE_SPINLOCK(wusb_cluster_ids_lock); | ||
278 | |||
279 | /* | ||
280 | * Get a WUSB Cluster ID | ||
281 | * | ||
282 | * Need to release with wusb_cluster_id_put() when done w/ it. | ||
283 | */ | ||
284 | /* FIXME: coordinate with the choose_addres() from the USB stack */ | ||
285 | /* we want to leave the top of the 128 range for cluster addresses and | ||
286 | * the bottom for device addresses (as we map them one on one with | ||
287 | * ports). */ | ||
288 | u8 wusb_cluster_id_get(void) | ||
289 | { | ||
290 | u8 id; | ||
291 | spin_lock(&wusb_cluster_ids_lock); | ||
292 | id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS); | ||
293 | if (id > CLUSTER_IDS) { | ||
294 | id = 0; | ||
295 | goto out; | ||
296 | } | ||
297 | set_bit(id, wusb_cluster_id_table); | ||
298 | id = (u8) 0xff - id; | ||
299 | out: | ||
300 | spin_unlock(&wusb_cluster_ids_lock); | ||
301 | return id; | ||
302 | |||
303 | } | ||
304 | EXPORT_SYMBOL_GPL(wusb_cluster_id_get); | ||
305 | |||
306 | /* | ||
307 | * Release a WUSB Cluster ID | ||
308 | * | ||
309 | * Obtained it with wusb_cluster_id_get() | ||
310 | */ | ||
311 | void wusb_cluster_id_put(u8 id) | ||
312 | { | ||
313 | id = 0xff - id; | ||
314 | BUG_ON(id >= CLUSTER_IDS); | ||
315 | spin_lock(&wusb_cluster_ids_lock); | ||
316 | WARN_ON(!test_bit(id, wusb_cluster_id_table)); | ||
317 | clear_bit(id, wusb_cluster_id_table); | ||
318 | spin_unlock(&wusb_cluster_ids_lock); | ||
319 | } | ||
320 | EXPORT_SYMBOL_GPL(wusb_cluster_id_put); | ||
321 | |||
322 | /** | ||
323 | * wusbhc_giveback_urb - return an URB to the USB core | ||
324 | * @wusbhc: the host controller the URB is from. | ||
325 | * @urb: the URB. | ||
326 | * @status: the URB's status. | ||
327 | * | ||
328 | * Return an URB to the USB core doing some additional WUSB specific | ||
329 | * processing. | ||
330 | * | ||
331 | * - After a successful transfer, update the trust timeout timestamp | ||
332 | * for the WUSB device. | ||
333 | * | ||
334 | * - [WUSB] sections 4.13 and 7.5.1 specifies the stop retrasmittion | ||
335 | * condition for the WCONNECTACK_IE is that the host has observed | ||
336 | * the associated device responding to a control transfer. | ||
337 | */ | ||
338 | void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status) | ||
339 | { | ||
340 | struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); | ||
341 | |||
342 | if (status == 0) { | ||
343 | wusb_dev->entry_ts = jiffies; | ||
344 | |||
345 | /* wusbhc_devconnect_acked() can't be called from from | ||
346 | atomic context so defer it to a work queue. */ | ||
347 | if (!list_empty(&wusb_dev->cack_node)) | ||
348 | queue_work(wusbd, &wusb_dev->devconnect_acked_work); | ||
349 | } | ||
350 | |||
351 | usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status); | ||
352 | } | ||
353 | EXPORT_SYMBOL_GPL(wusbhc_giveback_urb); | ||
354 | |||
355 | /** | ||
356 | * wusbhc_reset_all - reset the HC hardware | ||
357 | * @wusbhc: the host controller to reset. | ||
358 | * | ||
359 | * Request a full hardware reset of the chip. This will also reset | ||
360 | * the radio controller and any other PALs. | ||
361 | */ | ||
362 | void wusbhc_reset_all(struct wusbhc *wusbhc) | ||
363 | { | ||
364 | uwb_rc_reset_all(wusbhc->uwb_rc); | ||
365 | } | ||
366 | EXPORT_SYMBOL_GPL(wusbhc_reset_all); | ||
367 | |||
368 | static struct notifier_block wusb_usb_notifier = { | ||
369 | .notifier_call = wusb_usb_ncb, | ||
370 | .priority = INT_MAX /* Need to be called first of all */ | ||
371 | }; | ||
372 | |||
373 | static int __init wusbcore_init(void) | ||
374 | { | ||
375 | int result; | ||
376 | result = wusb_crypto_init(); | ||
377 | if (result < 0) | ||
378 | goto error_crypto_init; | ||
379 | /* WQ is singlethread because we need to serialize notifications */ | ||
380 | wusbd = create_singlethread_workqueue("wusbd"); | ||
381 | if (wusbd == NULL) { | ||
382 | result = -ENOMEM; | ||
383 | printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n"); | ||
384 | goto error_wusbd_create; | ||
385 | } | ||
386 | usb_register_notify(&wusb_usb_notifier); | ||
387 | bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS); | ||
388 | set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */ | ||
389 | return 0; | ||
390 | |||
391 | error_wusbd_create: | ||
392 | wusb_crypto_exit(); | ||
393 | error_crypto_init: | ||
394 | return result; | ||
395 | |||
396 | } | ||
397 | module_init(wusbcore_init); | ||
398 | |||
399 | static void __exit wusbcore_exit(void) | ||
400 | { | ||
401 | clear_bit(0, wusb_cluster_id_table); | ||
402 | if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) { | ||
403 | char buf[256]; | ||
404 | bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table, | ||
405 | CLUSTER_IDS); | ||
406 | printk(KERN_ERR "BUG: WUSB Cluster IDs not released " | ||
407 | "on exit: %s\n", buf); | ||
408 | WARN_ON(1); | ||
409 | } | ||
410 | usb_unregister_notify(&wusb_usb_notifier); | ||
411 | destroy_workqueue(wusbd); | ||
412 | wusb_crypto_exit(); | ||
413 | } | ||
414 | module_exit(wusbcore_exit); | ||
415 | |||
416 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
417 | MODULE_DESCRIPTION("Wireless USB core"); | ||
418 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h new file mode 100644 index 000000000000..d0c132434f1b --- /dev/null +++ b/drivers/usb/wusbcore/wusbhc.h | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Wireless USB Host Controller | ||
3 | * Common infrastructure for WHCI and HWA WUSB-HC drivers | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * This driver implements parts common to all Wireless USB Host | ||
25 | * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used | ||
26 | * by: | ||
27 | * | ||
28 | * - hwahc: HWA, USB-dongle that implements a Wireless USB host | ||
29 | * controller, (Wireless USB 1.0 Host-Wire-Adapter specification). | ||
30 | * | ||
31 | * - whci: WHCI, a PCI card with a wireless host controller | ||
32 | * (Wireless Host Controller Interface 1.0 specification). | ||
33 | * | ||
34 | * Check out the Design-overview.txt file in the source documentation | ||
35 | * for other details on the implementation. | ||
36 | * | ||
37 | * Main blocks: | ||
38 | * | ||
39 | * rh Root Hub emulation (part of the HCD glue) | ||
40 | * | ||
41 | * devconnect Handle all the issues related to device connection, | ||
42 | * authentication, disconnection, timeout, reseting, | ||
43 | * keepalives, etc. | ||
44 | * | ||
45 | * mmc MMC IE broadcasting handling | ||
46 | * | ||
47 | * A host controller driver just initializes its stuff and as part of | ||
48 | * that, creates a 'struct wusbhc' instance that handles all the | ||
49 | * common WUSB mechanisms. Links in the function ops that are specific | ||
50 | * to it and then registers the host controller. Ready to run. | ||
51 | */ | ||
52 | |||
53 | #ifndef __WUSBHC_H__ | ||
54 | #define __WUSBHC_H__ | ||
55 | |||
56 | #include <linux/usb.h> | ||
57 | #include <linux/list.h> | ||
58 | #include <linux/mutex.h> | ||
59 | #include <linux/kref.h> | ||
60 | #include <linux/workqueue.h> | ||
61 | /* FIXME: Yes, I know: BAD--it's not my fault the USB HC iface is not | ||
62 | * public */ | ||
63 | #include <linux/../../drivers/usb/core/hcd.h> | ||
64 | #include <linux/uwb.h> | ||
65 | #include <linux/usb/wusb.h> | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Wireless USB device | ||
70 | * | ||
71 | * Describe a WUSB device connected to the cluster. This struct | ||
72 | * belongs to the 'struct wusb_port' it is attached to and it is | ||
73 | * responsible for putting and clearing the pointer to it. | ||
74 | * | ||
75 | * Note this "complements" the 'struct usb_device' that the usb_hcd | ||
76 | * keeps for each connected USB device. However, it extends some | ||
77 | * information that is not available (there is no hcpriv ptr in it!) | ||
78 | * *and* most importantly, it's life cycle is different. It is created | ||
79 | * as soon as we get a DN_Connect (connect request notification) from | ||
80 | * the device through the WUSB host controller; the USB stack doesn't | ||
81 | * create the device until we authenticate it. FIXME: this will | ||
82 | * change. | ||
83 | * | ||
84 | * @bos: This is allocated when the BOS descriptors are read from | ||
85 | * the device and freed upon the wusb_dev struct dying. | ||
86 | * @wusb_cap_descr: points into @bos, and has been verified to be size | ||
87 | * safe. | ||
88 | */ | ||
89 | struct wusb_dev { | ||
90 | struct kref refcnt; | ||
91 | struct wusbhc *wusbhc; | ||
92 | struct list_head cack_node; /* Connect-Ack list */ | ||
93 | u8 port_idx; | ||
94 | u8 addr; | ||
95 | u8 beacon_type:4; | ||
96 | struct usb_encryption_descriptor ccm1_etd; | ||
97 | struct wusb_ckhdid cdid; | ||
98 | unsigned long entry_ts; | ||
99 | struct usb_bos_descriptor *bos; | ||
100 | struct usb_wireless_cap_descriptor *wusb_cap_descr; | ||
101 | struct uwb_mas_bm availability; | ||
102 | struct work_struct devconnect_acked_work; | ||
103 | struct urb *set_gtk_urb; | ||
104 | struct usb_ctrlrequest *set_gtk_req; | ||
105 | struct usb_device *usb_dev; | ||
106 | }; | ||
107 | |||
108 | #define WUSB_DEV_ADDR_UNAUTH 0x80 | ||
109 | |||
110 | static inline void wusb_dev_init(struct wusb_dev *wusb_dev) | ||
111 | { | ||
112 | kref_init(&wusb_dev->refcnt); | ||
113 | /* no need to init the cack_node */ | ||
114 | } | ||
115 | |||
116 | extern void wusb_dev_destroy(struct kref *_wusb_dev); | ||
117 | |||
118 | static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev) | ||
119 | { | ||
120 | kref_get(&wusb_dev->refcnt); | ||
121 | return wusb_dev; | ||
122 | } | ||
123 | |||
124 | static inline void wusb_dev_put(struct wusb_dev *wusb_dev) | ||
125 | { | ||
126 | kref_put(&wusb_dev->refcnt, wusb_dev_destroy); | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * Wireless USB Host Controlller root hub "fake" ports | ||
131 | * (state and device information) | ||
132 | * | ||
133 | * Wireless USB is wireless, so there are no ports; but we | ||
134 | * fake'em. Each RC can connect a max of devices at the same time | ||
135 | * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's | ||
136 | * caps), referred to in wusbhc->ports_max. | ||
137 | * | ||
138 | * See rh.c for more information. | ||
139 | * | ||
140 | * The @status and @change use the same bits as in USB2.0[11.24.2.7], | ||
141 | * so we don't have to do much when getting the port's status. | ||
142 | * | ||
143 | * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10], | ||
144 | * include/linux/usb_ch9.h (#define USB_PORT_STAT_*) | ||
145 | */ | ||
146 | struct wusb_port { | ||
147 | u16 status; | ||
148 | u16 change; | ||
149 | struct wusb_dev *wusb_dev; /* connected device's info */ | ||
150 | unsigned reset_count; | ||
151 | u32 ptk_tkid; | ||
152 | }; | ||
153 | |||
154 | /** | ||
155 | * WUSB Host Controller specifics | ||
156 | * | ||
157 | * All fields that are common to all Wireless USB controller types | ||
158 | * (HWA and WHCI) are grouped here. Host Controller | ||
159 | * functions/operations that only deal with general Wireless USB HC | ||
160 | * issues use this data type to refer to the host. | ||
161 | * | ||
162 | * @usb_hcd Instantiation of a USB host controller | ||
163 | * (initialized by upper layer [HWA=HC or WHCI]. | ||
164 | * | ||
165 | * @dev Device that implements this; initialized by the | ||
166 | * upper layer (HWA-HC, WHCI...); this device should | ||
167 | * have a refcount. | ||
168 | * | ||
169 | * @trust_timeout After this time without hearing for device | ||
170 | * activity, we consider the device gone and we have to | ||
171 | * re-authenticate. | ||
172 | * | ||
173 | * Can be accessed w/o locking--however, read to a | ||
174 | * local variable then use. | ||
175 | * | ||
176 | * @chid WUSB Cluster Host ID: this is supposed to be a | ||
177 | * unique value that doesn't change across reboots (so | ||
178 | * that your devices do not require re-association). | ||
179 | * | ||
180 | * Read/Write protected by @mutex | ||
181 | * | ||
182 | * @dev_info This array has ports_max elements. It is used to | ||
183 | * give the HC information about the WUSB devices (see | ||
184 | * 'struct wusb_dev_info'). | ||
185 | * | ||
186 | * For HWA we need to allocate it in heap; for WHCI it | ||
187 | * needs to be permanently mapped, so we keep it for | ||
188 | * both and make it easy. Call wusbhc->dev_info_set() | ||
189 | * to update an entry. | ||
190 | * | ||
191 | * @ports_max Number of simultaneous device connections (fake | ||
192 | * ports) this HC will take. Read-only. | ||
193 | * | ||
194 | * @port Array of port status for each fake root port. Guaranteed to | ||
195 | * always be the same lenght during device existence | ||
196 | * [this allows for some unlocked but referenced reading]. | ||
197 | * | ||
198 | * @mmcies_max Max number of Information Elements this HC can send | ||
199 | * in its MMC. Read-only. | ||
200 | * | ||
201 | * @mmcie_add HC specific operation (WHCI or HWA) for adding an | ||
202 | * MMCIE. | ||
203 | * | ||
204 | * @mmcie_rm HC specific operation (WHCI or HWA) for removing an | ||
205 | * MMCIE. | ||
206 | * | ||
207 | * @enc_types Array which describes the encryptions methods | ||
208 | * supported by the host as described in WUSB1.0 -- | ||
209 | * one entry per supported method. As of WUSB1.0 there | ||
210 | * is only four methods, we make space for eight just in | ||
211 | * case they decide to add some more (and pray they do | ||
212 | * it in sequential order). if 'enc_types[enc_method] | ||
213 | * != 0', then it is supported by the host. enc_method | ||
214 | * is USB_ENC_TYPE*. | ||
215 | * | ||
216 | * @set_ptk: Set the PTK and enable encryption for a device. Or, if | ||
217 | * the supplied key is NULL, disable encryption for that | ||
218 | * device. | ||
219 | * | ||
220 | * @set_gtk: Set the GTK to be used for all future broadcast packets | ||
221 | * (i.e., MMCs). With some hardware, setting the GTK may start | ||
222 | * MMC transmission. | ||
223 | * | ||
224 | * NOTE: | ||
225 | * | ||
226 | * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid | ||
227 | * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev | ||
228 | * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a | ||
229 | * refcount on it). | ||
230 | * | ||
231 | * Most of the times when you need to use it, it will be non-NULL, | ||
232 | * so there is no real need to check for it (wusb_dev will | ||
233 | * dissapear before usb_dev). | ||
234 | * | ||
235 | * - The following fields need to be filled out before calling | ||
236 | * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}. | ||
237 | * | ||
238 | * - there is no wusbhc_init() method, we do everything in | ||
239 | * wusbhc_create(). | ||
240 | * | ||
241 | * - Creation is done in two phases, wusbhc_create() and | ||
242 | * wusbhc_create_b(); b are the parts that need to be called after | ||
243 | * calling usb_hcd_add(&wusbhc->usb_hcd). | ||
244 | */ | ||
245 | struct wusbhc { | ||
246 | struct usb_hcd usb_hcd; /* HAS TO BE 1st */ | ||
247 | struct device *dev; | ||
248 | struct uwb_rc *uwb_rc; | ||
249 | struct uwb_pal pal; | ||
250 | |||
251 | unsigned trust_timeout; /* in jiffies */ | ||
252 | struct wuie_host_info *wuie_host_info; /* Includes CHID */ | ||
253 | |||
254 | struct mutex mutex; /* locks everything else */ | ||
255 | u16 cluster_id; /* Wireless USB Cluster ID */ | ||
256 | struct wusb_port *port; /* Fake port status handling */ | ||
257 | struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */ | ||
258 | u8 ports_max; | ||
259 | unsigned active:1; /* currently xmit'ing MMCs */ | ||
260 | struct wuie_keep_alive keep_alive_ie; /* protected by mutex */ | ||
261 | struct delayed_work keep_alive_timer; | ||
262 | struct list_head cack_list; /* Connect acknowledging */ | ||
263 | size_t cack_count; /* protected by 'mutex' */ | ||
264 | struct wuie_connect_ack cack_ie; | ||
265 | struct uwb_rsv *rsv; /* cluster bandwidth reservation */ | ||
266 | |||
267 | struct mutex mmcie_mutex; /* MMC WUIE handling */ | ||
268 | struct wuie_hdr **mmcie; /* WUIE array */ | ||
269 | u8 mmcies_max; | ||
270 | /* FIXME: make wusbhc_ops? */ | ||
271 | int (*start)(struct wusbhc *wusbhc); | ||
272 | void (*stop)(struct wusbhc *wusbhc); | ||
273 | int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | ||
274 | u8 handle, struct wuie_hdr *wuie); | ||
275 | int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle); | ||
276 | int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev); | ||
277 | int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index, | ||
278 | const struct uwb_mas_bm *); | ||
279 | int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx, | ||
280 | u32 tkid, const void *key, size_t key_size); | ||
281 | int (*set_gtk)(struct wusbhc *wusbhc, | ||
282 | u32 tkid, const void *key, size_t key_size); | ||
283 | int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots); | ||
284 | |||
285 | struct { | ||
286 | struct usb_key_descriptor descr; | ||
287 | u8 data[16]; /* GTK key data */ | ||
288 | } __attribute__((packed)) gtk; | ||
289 | u8 gtk_index; | ||
290 | u32 gtk_tkid; | ||
291 | struct work_struct gtk_rekey_done_work; | ||
292 | int pending_set_gtks; | ||
293 | |||
294 | struct usb_encryption_descriptor *ccm1_etd; | ||
295 | }; | ||
296 | |||
297 | #define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd) | ||
298 | |||
299 | |||
300 | extern int wusbhc_create(struct wusbhc *); | ||
301 | extern int wusbhc_b_create(struct wusbhc *); | ||
302 | extern void wusbhc_b_destroy(struct wusbhc *); | ||
303 | extern void wusbhc_destroy(struct wusbhc *); | ||
304 | extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *, | ||
305 | struct wusb_dev *); | ||
306 | extern void wusb_dev_sysfs_rm(struct wusb_dev *); | ||
307 | extern int wusbhc_sec_create(struct wusbhc *); | ||
308 | extern int wusbhc_sec_start(struct wusbhc *); | ||
309 | extern void wusbhc_sec_stop(struct wusbhc *); | ||
310 | extern void wusbhc_sec_destroy(struct wusbhc *); | ||
311 | extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, | ||
312 | int status); | ||
313 | void wusbhc_reset_all(struct wusbhc *wusbhc); | ||
314 | |||
315 | int wusbhc_pal_register(struct wusbhc *wusbhc); | ||
316 | void wusbhc_pal_unregister(struct wusbhc *wusbhc); | ||
317 | |||
318 | /* | ||
319 | * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone | ||
320 | * | ||
321 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) | ||
322 | * | ||
323 | * This is a safe assumption as @usb_dev->bus is referenced all the | ||
324 | * time during the @usb_dev life cycle. | ||
325 | */ | ||
326 | static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev) | ||
327 | { | ||
328 | struct usb_hcd *usb_hcd; | ||
329 | usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self); | ||
330 | return usb_get_hcd(usb_hcd); | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Increment the reference count on a wusbhc. | ||
335 | * | ||
336 | * @wusbhc's life cycle is identical to that of the underlying usb_hcd. | ||
337 | */ | ||
338 | static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc) | ||
339 | { | ||
340 | return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Return the wusbhc associated to a @usb_dev | ||
345 | * | ||
346 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) | ||
347 | * | ||
348 | * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down. | ||
349 | * WARNING: referenced at the usb_hcd level, unlocked | ||
350 | * | ||
351 | * FIXME: move offline | ||
352 | */ | ||
353 | static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev) | ||
354 | { | ||
355 | struct wusbhc *wusbhc = NULL; | ||
356 | struct usb_hcd *usb_hcd; | ||
357 | if (usb_dev->devnum > 1 && !usb_dev->wusb) { | ||
358 | /* but root hubs */ | ||
359 | dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum, | ||
360 | usb_dev->wusb); | ||
361 | BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb); | ||
362 | } | ||
363 | usb_hcd = usb_hcd_get_by_usb_dev(usb_dev); | ||
364 | if (usb_hcd == NULL) | ||
365 | return NULL; | ||
366 | BUG_ON(usb_hcd->wireless == 0); | ||
367 | return wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
368 | } | ||
369 | |||
370 | |||
371 | static inline void wusbhc_put(struct wusbhc *wusbhc) | ||
372 | { | ||
373 | usb_put_hcd(&wusbhc->usb_hcd); | ||
374 | } | ||
375 | |||
376 | int wusbhc_start(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid); | ||
377 | void wusbhc_stop(struct wusbhc *wusbhc); | ||
378 | extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); | ||
379 | |||
380 | /* Device connect handling */ | ||
381 | extern int wusbhc_devconnect_create(struct wusbhc *); | ||
382 | extern void wusbhc_devconnect_destroy(struct wusbhc *); | ||
383 | extern int wusbhc_devconnect_start(struct wusbhc *wusbhc, | ||
384 | const struct wusb_ckhdid *chid); | ||
385 | extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); | ||
386 | extern int wusbhc_devconnect_auth(struct wusbhc *, u8); | ||
387 | extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, | ||
388 | struct wusb_dn_hdr *dn_hdr, size_t size); | ||
389 | extern int wusbhc_dev_reset(struct wusbhc *wusbhc, u8 port); | ||
390 | extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port); | ||
391 | extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
392 | void *priv); | ||
393 | extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, | ||
394 | u8 addr); | ||
395 | |||
396 | /* Wireless USB fake Root Hub methods */ | ||
397 | extern int wusbhc_rh_create(struct wusbhc *); | ||
398 | extern void wusbhc_rh_destroy(struct wusbhc *); | ||
399 | |||
400 | extern int wusbhc_rh_status_data(struct usb_hcd *, char *); | ||
401 | extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16); | ||
402 | extern int wusbhc_rh_suspend(struct usb_hcd *); | ||
403 | extern int wusbhc_rh_resume(struct usb_hcd *); | ||
404 | extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned); | ||
405 | |||
406 | /* MMC handling */ | ||
407 | extern int wusbhc_mmcie_create(struct wusbhc *); | ||
408 | extern void wusbhc_mmcie_destroy(struct wusbhc *); | ||
409 | extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt, | ||
410 | struct wuie_hdr *); | ||
411 | extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *); | ||
412 | |||
413 | /* Bandwidth reservation */ | ||
414 | int wusbhc_rsv_establish(struct wusbhc *wusbhc); | ||
415 | void wusbhc_rsv_terminate(struct wusbhc *wusbhc); | ||
416 | |||
417 | /* | ||
418 | * I've always said | ||
419 | * I wanted a wedding in a church... | ||
420 | * | ||
421 | * but lately I've been thinking about | ||
422 | * the Botanical Gardens. | ||
423 | * | ||
424 | * We could do it by the tulips. | ||
425 | * It'll be beautiful | ||
426 | * | ||
427 | * --Security! | ||
428 | */ | ||
429 | extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *, | ||
430 | struct wusb_dev *); | ||
431 | extern void wusb_dev_sec_rm(struct wusb_dev *) ; | ||
432 | extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *, | ||
433 | struct wusb_ckhdid *ck); | ||
434 | void wusbhc_gtk_rekey(struct wusbhc *wusbhc); | ||
435 | |||
436 | |||
437 | /* WUSB Cluster ID handling */ | ||
438 | extern u8 wusb_cluster_id_get(void); | ||
439 | extern void wusb_cluster_id_put(u8); | ||
440 | |||
441 | /* | ||
442 | * wusb_port_by_idx - return the port associated to a zero-based port index | ||
443 | * | ||
444 | * NOTE: valid without locking as long as wusbhc is referenced (as the | ||
445 | * number of ports doesn't change). The data pointed to has to | ||
446 | * be verified though :) | ||
447 | */ | ||
448 | static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc, | ||
449 | u8 port_idx) | ||
450 | { | ||
451 | return &wusbhc->port[port_idx]; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to | ||
456 | * a port_idx. | ||
457 | * | ||
458 | * USB stack USB ports are 1 based!! | ||
459 | * | ||
460 | * NOTE: only valid for WUSB devices!!! | ||
461 | */ | ||
462 | static inline u8 wusb_port_no_to_idx(u8 port_no) | ||
463 | { | ||
464 | return port_no - 1; | ||
465 | } | ||
466 | |||
467 | extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *, | ||
468 | struct usb_device *); | ||
469 | |||
470 | /* | ||
471 | * Return a referenced wusb_dev given a @usb_dev | ||
472 | * | ||
473 | * Returns NULL if the usb_dev is being torn down. | ||
474 | * | ||
475 | * FIXME: move offline | ||
476 | */ | ||
477 | static inline | ||
478 | struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev) | ||
479 | { | ||
480 | struct wusbhc *wusbhc; | ||
481 | struct wusb_dev *wusb_dev; | ||
482 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); | ||
483 | if (wusbhc == NULL) | ||
484 | return NULL; | ||
485 | mutex_lock(&wusbhc->mutex); | ||
486 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); | ||
487 | mutex_unlock(&wusbhc->mutex); | ||
488 | wusbhc_put(wusbhc); | ||
489 | return wusb_dev; | ||
490 | } | ||
491 | |||
492 | /* Misc */ | ||
493 | |||
494 | extern struct workqueue_struct *wusbd; | ||
495 | #endif /* #ifndef __WUSBHC_H__ */ | ||
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig new file mode 100644 index 000000000000..ca783127af36 --- /dev/null +++ b/drivers/uwb/Kconfig | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # UWB device configuration | ||
3 | # | ||
4 | |||
5 | menuconfig UWB | ||
6 | tristate "Ultra Wideband devices (EXPERIMENTAL)" | ||
7 | depends on EXPERIMENTAL | ||
8 | depends on PCI | ||
9 | default n | ||
10 | help | ||
11 | UWB is a high-bandwidth, low-power, point-to-point radio | ||
12 | technology using a wide spectrum (3.1-10.6GHz). It is | ||
13 | optimized for in-room use (480Mbps at 2 meters, 110Mbps at | ||
14 | 10m). It serves as the transport layer for other protocols, | ||
15 | such as Wireless USB (WUSB), IP (WLP) and upcoming | ||
16 | Bluetooth and 1394 | ||
17 | |||
18 | The topology is peer to peer; however, higher level | ||
19 | protocols (such as WUSB) might impose a master/slave | ||
20 | relationship. | ||
21 | |||
22 | Say Y here if your computer has UWB radio controllers (USB or PCI) | ||
23 | based. You will need to enable the radio controllers | ||
24 | below. It is ok to select all of them, no harm done. | ||
25 | |||
26 | For more help check the UWB and WUSB related files in | ||
27 | <file:Documentation/usb/>. | ||
28 | |||
29 | To compile the UWB stack as a module, choose M here. | ||
30 | |||
31 | if UWB | ||
32 | |||
33 | config UWB_HWA | ||
34 | tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)" | ||
35 | depends on USB | ||
36 | help | ||
37 | This driver enables the radio controller for HWA USB | ||
38 | devices. HWA stands for Host Wire Adapter, and it is a UWB | ||
39 | Radio Controller connected to your system via USB. Most of | ||
40 | them come with a Wireless USB host controller also. | ||
41 | |||
42 | To compile this driver select Y (built in) or M (module). It | ||
43 | is safe to select any even if you do not have the hardware. | ||
44 | |||
45 | config UWB_WHCI | ||
46 | tristate "UWB Radio Control driver for WHCI-compliant cards" | ||
47 | depends on PCI | ||
48 | help | ||
49 | This driver enables the radio controller for WHCI cards. | ||
50 | |||
51 | WHCI is an specification developed by Intel | ||
52 | (http://www.intel.com/technology/comms/wusb/whci.htm) much | ||
53 | in the spirit of USB's EHCI, but for UWB and Wireless USB | ||
54 | radio/host controllers connected via memmory mapping (eg: | ||
55 | PCI). Most of these cards come also with a Wireless USB host | ||
56 | controller. | ||
57 | |||
58 | To compile this driver select Y (built in) or M (module). It | ||
59 | is safe to select any even if you do not have the hardware. | ||
60 | |||
61 | config UWB_WLP | ||
62 | tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)" | ||
63 | depends on UWB && NET | ||
64 | help | ||
65 | This is a common library for drivers that implement | ||
66 | networking over UWB. | ||
67 | |||
68 | config UWB_I1480U | ||
69 | tristate "Support for Intel Wireless UWB Link 1480 HWA" | ||
70 | depends on UWB_HWA | ||
71 | select FW_LOADER | ||
72 | help | ||
73 | This driver enables support for the i1480 when connected via | ||
74 | USB. It consists of a firmware uploader that will enable it | ||
75 | to behave as an HWA device. | ||
76 | |||
77 | To compile this driver select Y (built in) or M (module). It | ||
78 | is safe to select any even if you do not have the hardware. | ||
79 | |||
80 | config UWB_I1480U_WLP | ||
81 | tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface" | ||
82 | depends on UWB_I1480U && UWB_WLP && NET | ||
83 | help | ||
84 | This driver enables WLP support for the i1480 when connected via | ||
85 | USB. WLP is the WiMedia Link Protocol, or IP over UWB. | ||
86 | |||
87 | To compile this driver select Y (built in) or M (module). It | ||
88 | is safe to select any even if you don't have the hardware. | ||
89 | |||
90 | endif # UWB | ||
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile new file mode 100644 index 000000000000..257e6908304c --- /dev/null +++ b/drivers/uwb/Makefile | |||
@@ -0,0 +1,29 @@ | |||
1 | obj-$(CONFIG_UWB) += uwb.o | ||
2 | obj-$(CONFIG_UWB_WLP) += wlp/ | ||
3 | obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o | ||
4 | obj-$(CONFIG_UWB_HWA) += hwa-rc.o | ||
5 | obj-$(CONFIG_UWB_I1480U) += i1480/ | ||
6 | |||
7 | uwb-objs := \ | ||
8 | address.o \ | ||
9 | beacon.o \ | ||
10 | driver.o \ | ||
11 | drp.o \ | ||
12 | drp-avail.o \ | ||
13 | drp-ie.o \ | ||
14 | est.o \ | ||
15 | ie.o \ | ||
16 | lc-dev.o \ | ||
17 | lc-rc.o \ | ||
18 | neh.o \ | ||
19 | pal.o \ | ||
20 | reset.o \ | ||
21 | rsv.o \ | ||
22 | scan.o \ | ||
23 | uwb-debug.o \ | ||
24 | uwbd.o | ||
25 | |||
26 | umc-objs := \ | ||
27 | umc-bus.o \ | ||
28 | umc-dev.o \ | ||
29 | umc-drv.o | ||
diff --git a/drivers/uwb/address.c b/drivers/uwb/address.c new file mode 100644 index 000000000000..1664ae5f1706 --- /dev/null +++ b/drivers/uwb/address.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Address management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/errno.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/random.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/uwb/debug.h> | ||
32 | #include "uwb-internal.h" | ||
33 | |||
34 | |||
35 | /** Device Address Management command */ | ||
36 | struct uwb_rc_cmd_dev_addr_mgmt { | ||
37 | struct uwb_rccb rccb; | ||
38 | u8 bmOperationType; | ||
39 | u8 baAddr[6]; | ||
40 | } __attribute__((packed)); | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Low level command for setting/getting UWB radio's addresses | ||
45 | * | ||
46 | * @hwarc: HWA Radio Control interface instance | ||
47 | * @bmOperationType: | ||
48 | * Set/get, MAC/DEV (see WUSB1.0[8.6.2.2]) | ||
49 | * @baAddr: address buffer--assumed to have enough data to hold | ||
50 | * the address type requested. | ||
51 | * @reply: Pointer to reply buffer (can be stack allocated) | ||
52 | * @returns: 0 if ok, < 0 errno code on error. | ||
53 | * | ||
54 | * @cmd has to be allocated because USB cannot grok USB or vmalloc | ||
55 | * buffers depending on your combination of host architecture. | ||
56 | */ | ||
57 | static | ||
58 | int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc, | ||
59 | u8 bmOperationType, const u8 *baAddr, | ||
60 | struct uwb_rc_evt_dev_addr_mgmt *reply) | ||
61 | { | ||
62 | int result; | ||
63 | struct uwb_rc_cmd_dev_addr_mgmt *cmd; | ||
64 | |||
65 | result = -ENOMEM; | ||
66 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
67 | if (cmd == NULL) | ||
68 | goto error_kzalloc; | ||
69 | cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
70 | cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT); | ||
71 | cmd->bmOperationType = bmOperationType; | ||
72 | if (baAddr) { | ||
73 | size_t size = 0; | ||
74 | switch (bmOperationType >> 1) { | ||
75 | case 0: size = 2; break; | ||
76 | case 1: size = 6; break; | ||
77 | default: BUG(); | ||
78 | } | ||
79 | memcpy(cmd->baAddr, baAddr, size); | ||
80 | } | ||
81 | reply->rceb.bEventType = UWB_RC_CET_GENERAL; | ||
82 | reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT; | ||
83 | result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT", | ||
84 | &cmd->rccb, sizeof(*cmd), | ||
85 | &reply->rceb, sizeof(*reply)); | ||
86 | if (result < 0) | ||
87 | goto error_cmd; | ||
88 | if (result < sizeof(*reply)) { | ||
89 | dev_err(&rc->uwb_dev.dev, | ||
90 | "DEV-ADDR-MGMT: not enough data replied: " | ||
91 | "%d vs %zu bytes needed\n", result, sizeof(*reply)); | ||
92 | result = -ENOMSG; | ||
93 | } else if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
94 | dev_err(&rc->uwb_dev.dev, | ||
95 | "DEV-ADDR-MGMT: command execution failed: %s (%d)\n", | ||
96 | uwb_rc_strerror(reply->bResultCode), | ||
97 | reply->bResultCode); | ||
98 | result = -EIO; | ||
99 | } else | ||
100 | result = 0; | ||
101 | error_cmd: | ||
102 | kfree(cmd); | ||
103 | error_kzalloc: | ||
104 | return result; | ||
105 | } | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Set the UWB RC MAC or device address. | ||
110 | * | ||
111 | * @rc: UWB Radio Controller | ||
112 | * @_addr: Pointer to address to write [assumed to be either a | ||
113 | * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *']. | ||
114 | * @type: Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC). | ||
115 | * @returns: 0 if ok, < 0 errno code on error. | ||
116 | * | ||
117 | * Some anal retentivity here: even if both 'struct | ||
118 | * uwb_{dev,mac}_addr' have the actual byte array in the same offset | ||
119 | * and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer | ||
120 | * to use some syntatic sugar in case someday we decide to change the | ||
121 | * format of the structs. The compiler will optimize it out anyway. | ||
122 | */ | ||
123 | static int uwb_rc_addr_set(struct uwb_rc *rc, | ||
124 | const void *_addr, enum uwb_addr_type type) | ||
125 | { | ||
126 | int result; | ||
127 | u8 bmOperationType = 0x1; /* Set address */ | ||
128 | const struct uwb_dev_addr *dev_addr = _addr; | ||
129 | const struct uwb_mac_addr *mac_addr = _addr; | ||
130 | struct uwb_rc_evt_dev_addr_mgmt reply; | ||
131 | const u8 *baAddr; | ||
132 | |||
133 | result = -EINVAL; | ||
134 | switch (type) { | ||
135 | case UWB_ADDR_DEV: | ||
136 | baAddr = dev_addr->data; | ||
137 | break; | ||
138 | case UWB_ADDR_MAC: | ||
139 | baAddr = mac_addr->data; | ||
140 | bmOperationType |= 0x2; | ||
141 | break; | ||
142 | default: | ||
143 | return result; | ||
144 | } | ||
145 | return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply); | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Get the UWB radio's MAC or device address. | ||
151 | * | ||
152 | * @rc: UWB Radio Controller | ||
153 | * @_addr: Where to write the address data [assumed to be either a | ||
154 | * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *']. | ||
155 | * @type: Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC). | ||
156 | * @returns: 0 if ok (and *_addr set), < 0 errno code on error. | ||
157 | * | ||
158 | * See comment in uwb_rc_addr_set() about anal retentivity in the | ||
159 | * type handling of the address variables. | ||
160 | */ | ||
161 | static int uwb_rc_addr_get(struct uwb_rc *rc, | ||
162 | void *_addr, enum uwb_addr_type type) | ||
163 | { | ||
164 | int result; | ||
165 | u8 bmOperationType = 0x0; /* Get address */ | ||
166 | struct uwb_rc_evt_dev_addr_mgmt evt; | ||
167 | struct uwb_dev_addr *dev_addr = _addr; | ||
168 | struct uwb_mac_addr *mac_addr = _addr; | ||
169 | u8 *baAddr; | ||
170 | |||
171 | result = -EINVAL; | ||
172 | switch (type) { | ||
173 | case UWB_ADDR_DEV: | ||
174 | baAddr = dev_addr->data; | ||
175 | break; | ||
176 | case UWB_ADDR_MAC: | ||
177 | bmOperationType |= 0x2; | ||
178 | baAddr = mac_addr->data; | ||
179 | break; | ||
180 | default: | ||
181 | return result; | ||
182 | } | ||
183 | result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt); | ||
184 | if (result == 0) | ||
185 | switch (type) { | ||
186 | case UWB_ADDR_DEV: | ||
187 | memcpy(&dev_addr->data, evt.baAddr, | ||
188 | sizeof(dev_addr->data)); | ||
189 | break; | ||
190 | case UWB_ADDR_MAC: | ||
191 | memcpy(&mac_addr->data, evt.baAddr, | ||
192 | sizeof(mac_addr->data)); | ||
193 | break; | ||
194 | default: /* shut gcc up */ | ||
195 | BUG(); | ||
196 | } | ||
197 | return result; | ||
198 | } | ||
199 | |||
200 | |||
201 | /** Get @rc's MAC address to @addr */ | ||
202 | int uwb_rc_mac_addr_get(struct uwb_rc *rc, | ||
203 | struct uwb_mac_addr *addr) { | ||
204 | return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC); | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get); | ||
207 | |||
208 | |||
209 | /** Get @rc's device address to @addr */ | ||
210 | int uwb_rc_dev_addr_get(struct uwb_rc *rc, | ||
211 | struct uwb_dev_addr *addr) { | ||
212 | return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV); | ||
213 | } | ||
214 | EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get); | ||
215 | |||
216 | |||
217 | /** Set @rc's address to @addr */ | ||
218 | int uwb_rc_mac_addr_set(struct uwb_rc *rc, | ||
219 | const struct uwb_mac_addr *addr) | ||
220 | { | ||
221 | int result = -EINVAL; | ||
222 | mutex_lock(&rc->uwb_dev.mutex); | ||
223 | result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC); | ||
224 | mutex_unlock(&rc->uwb_dev.mutex); | ||
225 | return result; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** Set @rc's address to @addr */ | ||
230 | int uwb_rc_dev_addr_set(struct uwb_rc *rc, | ||
231 | const struct uwb_dev_addr *addr) | ||
232 | { | ||
233 | int result = -EINVAL; | ||
234 | mutex_lock(&rc->uwb_dev.mutex); | ||
235 | result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV); | ||
236 | rc->uwb_dev.dev_addr = *addr; | ||
237 | mutex_unlock(&rc->uwb_dev.mutex); | ||
238 | return result; | ||
239 | } | ||
240 | |||
241 | /* Returns !0 if given address is already assigned to device. */ | ||
242 | int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr) | ||
243 | { | ||
244 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
245 | struct uwb_mac_addr *addr = _addr; | ||
246 | |||
247 | if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr)) | ||
248 | return !0; | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /* Returns !0 if given address is already assigned to device. */ | ||
253 | int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr) | ||
254 | { | ||
255 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
256 | struct uwb_dev_addr *addr = _addr; | ||
257 | if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr)) | ||
258 | return !0; | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller | ||
264 | * @rc: the (local) radio controller device requiring a new DevAddr | ||
265 | * | ||
266 | * A new DevAddr is required when: | ||
267 | * - first setting up a radio controller | ||
268 | * - if the hardware reports a DevAddr conflict | ||
269 | * | ||
270 | * The DevAddr is randomly generated in the generated DevAddr range | ||
271 | * [0x100, 0xfeff]. The number of devices in a beacon group is limited | ||
272 | * by mMaxBPLength (96) so this address space will never be exhausted. | ||
273 | * | ||
274 | * [ECMA-368] 17.1.1, 17.16. | ||
275 | */ | ||
276 | int uwb_rc_dev_addr_assign(struct uwb_rc *rc) | ||
277 | { | ||
278 | struct uwb_dev_addr new_addr; | ||
279 | |||
280 | do { | ||
281 | get_random_bytes(new_addr.data, sizeof(new_addr.data)); | ||
282 | } while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff | ||
283 | || __uwb_dev_addr_assigned(rc, &new_addr)); | ||
284 | |||
285 | return uwb_rc_dev_addr_set(rc, &new_addr); | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event | ||
290 | * @evt: the DEV_ADDR_CONFLICT notification from the radio controller | ||
291 | * | ||
292 | * A new (non-conflicting) DevAddr is assigned to the radio controller. | ||
293 | * | ||
294 | * [ECMA-368] 17.1.1.1. | ||
295 | */ | ||
296 | int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt) | ||
297 | { | ||
298 | struct uwb_rc *rc = evt->rc; | ||
299 | |||
300 | return uwb_rc_dev_addr_assign(rc); | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * Print the 48-bit EUI MAC address of the radio controller when | ||
305 | * reading /sys/class/uwb_rc/XX/mac_address | ||
306 | */ | ||
307 | static ssize_t uwb_rc_mac_addr_show(struct device *dev, | ||
308 | struct device_attribute *attr, char *buf) | ||
309 | { | ||
310 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
311 | struct uwb_rc *rc = uwb_dev->rc; | ||
312 | struct uwb_mac_addr addr; | ||
313 | ssize_t result; | ||
314 | |||
315 | mutex_lock(&rc->uwb_dev.mutex); | ||
316 | result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC); | ||
317 | mutex_unlock(&rc->uwb_dev.mutex); | ||
318 | if (result >= 0) { | ||
319 | result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr); | ||
320 | buf[result++] = '\n'; | ||
321 | } | ||
322 | return result; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address | ||
327 | * and if correct, set it. | ||
328 | */ | ||
329 | static ssize_t uwb_rc_mac_addr_store(struct device *dev, | ||
330 | struct device_attribute *attr, | ||
331 | const char *buf, size_t size) | ||
332 | { | ||
333 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
334 | struct uwb_rc *rc = uwb_dev->rc; | ||
335 | struct uwb_mac_addr addr; | ||
336 | ssize_t result; | ||
337 | |||
338 | result = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\n", | ||
339 | &addr.data[0], &addr.data[1], &addr.data[2], | ||
340 | &addr.data[3], &addr.data[4], &addr.data[5]); | ||
341 | if (result != 6) { | ||
342 | result = -EINVAL; | ||
343 | goto out; | ||
344 | } | ||
345 | if (is_multicast_ether_addr(addr.data)) { | ||
346 | dev_err(&rc->uwb_dev.dev, "refusing to set multicast " | ||
347 | "MAC address %s\n", buf); | ||
348 | result = -EINVAL; | ||
349 | goto out; | ||
350 | } | ||
351 | result = uwb_rc_mac_addr_set(rc, &addr); | ||
352 | if (result == 0) | ||
353 | rc->uwb_dev.mac_addr = addr; | ||
354 | out: | ||
355 | return result < 0 ? result : size; | ||
356 | } | ||
357 | DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store); | ||
358 | |||
359 | /** Print @addr to @buf, @return bytes written */ | ||
360 | size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr, | ||
361 | int type) | ||
362 | { | ||
363 | size_t result; | ||
364 | if (type) | ||
365 | result = scnprintf(buf, buf_size, | ||
366 | "%02x:%02x:%02x:%02x:%02x:%02x", | ||
367 | addr[0], addr[1], addr[2], | ||
368 | addr[3], addr[4], addr[5]); | ||
369 | else | ||
370 | result = scnprintf(buf, buf_size, "%02x:%02x", | ||
371 | addr[1], addr[0]); | ||
372 | return result; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(__uwb_addr_print); | ||
diff --git a/drivers/uwb/beacon.c b/drivers/uwb/beacon.c new file mode 100644 index 000000000000..46b18eec5026 --- /dev/null +++ b/drivers/uwb/beacon.c | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Beacon management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/err.h> | ||
31 | #include <linux/kdev_t.h> | ||
32 | #include "uwb-internal.h" | ||
33 | |||
34 | #define D_LOCAL 0 | ||
35 | #include <linux/uwb/debug.h> | ||
36 | |||
37 | /** Start Beaconing command structure */ | ||
38 | struct uwb_rc_cmd_start_beacon { | ||
39 | struct uwb_rccb rccb; | ||
40 | __le16 wBPSTOffset; | ||
41 | u8 bChannelNumber; | ||
42 | } __attribute__((packed)); | ||
43 | |||
44 | |||
45 | static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel) | ||
46 | { | ||
47 | int result; | ||
48 | struct uwb_rc_cmd_start_beacon *cmd; | ||
49 | struct uwb_rc_evt_confirm reply; | ||
50 | |||
51 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
52 | if (cmd == NULL) | ||
53 | return -ENOMEM; | ||
54 | cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
55 | cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON); | ||
56 | cmd->wBPSTOffset = cpu_to_le16(bpst_offset); | ||
57 | cmd->bChannelNumber = channel; | ||
58 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
59 | reply.rceb.wEvent = UWB_RC_CMD_START_BEACON; | ||
60 | result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd), | ||
61 | &reply.rceb, sizeof(reply)); | ||
62 | if (result < 0) | ||
63 | goto error_cmd; | ||
64 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
65 | dev_err(&rc->uwb_dev.dev, | ||
66 | "START-BEACON: command execution failed: %s (%d)\n", | ||
67 | uwb_rc_strerror(reply.bResultCode), reply.bResultCode); | ||
68 | result = -EIO; | ||
69 | } | ||
70 | error_cmd: | ||
71 | kfree(cmd); | ||
72 | return result; | ||
73 | } | ||
74 | |||
75 | static int uwb_rc_stop_beacon(struct uwb_rc *rc) | ||
76 | { | ||
77 | int result; | ||
78 | struct uwb_rccb *cmd; | ||
79 | struct uwb_rc_evt_confirm reply; | ||
80 | |||
81 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
82 | if (cmd == NULL) | ||
83 | return -ENOMEM; | ||
84 | cmd->bCommandType = UWB_RC_CET_GENERAL; | ||
85 | cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON); | ||
86 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
87 | reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON; | ||
88 | result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd), | ||
89 | &reply.rceb, sizeof(reply)); | ||
90 | if (result < 0) | ||
91 | goto error_cmd; | ||
92 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
93 | dev_err(&rc->uwb_dev.dev, | ||
94 | "STOP-BEACON: command execution failed: %s (%d)\n", | ||
95 | uwb_rc_strerror(reply.bResultCode), reply.bResultCode); | ||
96 | result = -EIO; | ||
97 | } | ||
98 | error_cmd: | ||
99 | kfree(cmd); | ||
100 | return result; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Start/stop beacons | ||
105 | * | ||
106 | * @rc: UWB Radio Controller to operate on | ||
107 | * @channel: UWB channel on which to beacon (WUSB[table | ||
108 | * 5-12]). If -1, stop beaconing. | ||
109 | * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero | ||
110 | * | ||
111 | * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB | ||
112 | * of a SET IE command after the device sent the first beacon that includes | ||
113 | * the IEs specified in the SET IE command. So, after we start beaconing we | ||
114 | * check if there is anything in the IE cache and call the SET IE command | ||
115 | * if needed. | ||
116 | */ | ||
117 | int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) | ||
118 | { | ||
119 | int result; | ||
120 | struct device *dev = &rc->uwb_dev.dev; | ||
121 | |||
122 | mutex_lock(&rc->uwb_dev.mutex); | ||
123 | if (channel < 0) | ||
124 | channel = -1; | ||
125 | if (channel == -1) | ||
126 | result = uwb_rc_stop_beacon(rc); | ||
127 | else { | ||
128 | /* channel >= 0...dah */ | ||
129 | result = uwb_rc_start_beacon(rc, bpst_offset, channel); | ||
130 | if (result < 0) | ||
131 | goto out_up; | ||
132 | if (le16_to_cpu(rc->ies->wIELength) > 0) { | ||
133 | result = uwb_rc_set_ie(rc, rc->ies); | ||
134 | if (result < 0) { | ||
135 | dev_err(dev, "Cannot set new IE on device: " | ||
136 | "%d\n", result); | ||
137 | result = uwb_rc_stop_beacon(rc); | ||
138 | channel = -1; | ||
139 | bpst_offset = 0; | ||
140 | } else | ||
141 | result = 0; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | if (result < 0) | ||
146 | goto out_up; | ||
147 | rc->beaconing = channel; | ||
148 | |||
149 | uwb_notify(rc, NULL, uwb_bg_joined(rc) ? UWB_NOTIF_BG_JOIN : UWB_NOTIF_BG_LEAVE); | ||
150 | |||
151 | out_up: | ||
152 | mutex_unlock(&rc->uwb_dev.mutex); | ||
153 | return result; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Beacon cache | ||
158 | * | ||
159 | * The purpose of this is to speed up the lookup of becon information | ||
160 | * when a new beacon arrives. The UWB Daemon uses it also to keep a | ||
161 | * tab of which devices are in radio distance and which not. When a | ||
162 | * device's beacon stays present for more than a certain amount of | ||
163 | * time, it is considered a new, usable device. When a beacon ceases | ||
164 | * to be received for a certain amount of time, it is considered that | ||
165 | * the device is gone. | ||
166 | * | ||
167 | * FIXME: use an allocator for the entries | ||
168 | * FIXME: use something faster for search than a list | ||
169 | */ | ||
170 | |||
171 | struct uwb_beca uwb_beca = { | ||
172 | .list = LIST_HEAD_INIT(uwb_beca.list), | ||
173 | .mutex = __MUTEX_INITIALIZER(uwb_beca.mutex) | ||
174 | }; | ||
175 | |||
176 | |||
177 | void uwb_bce_kfree(struct kref *_bce) | ||
178 | { | ||
179 | struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt); | ||
180 | |||
181 | kfree(bce->be); | ||
182 | kfree(bce); | ||
183 | } | ||
184 | |||
185 | |||
186 | /* Find a beacon by dev addr in the cache */ | ||
187 | static | ||
188 | struct uwb_beca_e *__uwb_beca_find_bydev(const struct uwb_dev_addr *dev_addr) | ||
189 | { | ||
190 | struct uwb_beca_e *bce, *next; | ||
191 | list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { | ||
192 | d_printf(6, NULL, "looking for addr %02x:%02x in %02x:%02x\n", | ||
193 | dev_addr->data[0], dev_addr->data[1], | ||
194 | bce->dev_addr.data[0], bce->dev_addr.data[1]); | ||
195 | if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr))) | ||
196 | goto out; | ||
197 | } | ||
198 | bce = NULL; | ||
199 | out: | ||
200 | return bce; | ||
201 | } | ||
202 | |||
203 | /* Find a beacon by dev addr in the cache */ | ||
204 | static | ||
205 | struct uwb_beca_e *__uwb_beca_find_bymac(const struct uwb_mac_addr *mac_addr) | ||
206 | { | ||
207 | struct uwb_beca_e *bce, *next; | ||
208 | list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { | ||
209 | if (!memcmp(bce->mac_addr, mac_addr->data, | ||
210 | sizeof(struct uwb_mac_addr))) | ||
211 | goto out; | ||
212 | } | ||
213 | bce = NULL; | ||
214 | out: | ||
215 | return bce; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr | ||
220 | * @rc: the radio controller that saw the device | ||
221 | * @devaddr: DevAddr of the UWB device to find | ||
222 | * | ||
223 | * There may be more than one matching device (in the case of a | ||
224 | * DevAddr conflict), but only the first one is returned. | ||
225 | */ | ||
226 | struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, | ||
227 | const struct uwb_dev_addr *devaddr) | ||
228 | { | ||
229 | struct uwb_dev *found = NULL; | ||
230 | struct uwb_beca_e *bce; | ||
231 | |||
232 | mutex_lock(&uwb_beca.mutex); | ||
233 | bce = __uwb_beca_find_bydev(devaddr); | ||
234 | if (bce) | ||
235 | found = uwb_dev_try_get(rc, bce->uwb_dev); | ||
236 | mutex_unlock(&uwb_beca.mutex); | ||
237 | |||
238 | return found; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48 | ||
243 | * @rc: the radio controller that saw the device | ||
244 | * @devaddr: EUI-48 of the UWB device to find | ||
245 | */ | ||
246 | struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, | ||
247 | const struct uwb_mac_addr *macaddr) | ||
248 | { | ||
249 | struct uwb_dev *found = NULL; | ||
250 | struct uwb_beca_e *bce; | ||
251 | |||
252 | mutex_lock(&uwb_beca.mutex); | ||
253 | bce = __uwb_beca_find_bymac(macaddr); | ||
254 | if (bce) | ||
255 | found = uwb_dev_try_get(rc, bce->uwb_dev); | ||
256 | mutex_unlock(&uwb_beca.mutex); | ||
257 | |||
258 | return found; | ||
259 | } | ||
260 | |||
261 | /* Initialize a beacon cache entry */ | ||
262 | static void uwb_beca_e_init(struct uwb_beca_e *bce) | ||
263 | { | ||
264 | mutex_init(&bce->mutex); | ||
265 | kref_init(&bce->refcnt); | ||
266 | stats_init(&bce->lqe_stats); | ||
267 | stats_init(&bce->rssi_stats); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Add a beacon to the cache | ||
272 | * | ||
273 | * @be: Beacon event information | ||
274 | * @bf: Beacon frame (part of b, really) | ||
275 | * @ts_jiffies: Timestamp (in jiffies) when the beacon was received | ||
276 | */ | ||
277 | struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be, | ||
278 | struct uwb_beacon_frame *bf, | ||
279 | unsigned long ts_jiffies) | ||
280 | { | ||
281 | struct uwb_beca_e *bce; | ||
282 | |||
283 | bce = kzalloc(sizeof(*bce), GFP_KERNEL); | ||
284 | if (bce == NULL) | ||
285 | return NULL; | ||
286 | uwb_beca_e_init(bce); | ||
287 | bce->ts_jiffies = ts_jiffies; | ||
288 | bce->uwb_dev = NULL; | ||
289 | list_add(&bce->node, &uwb_beca.list); | ||
290 | return bce; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Wipe out beacon entries that became stale | ||
295 | * | ||
296 | * Remove associated devicest too. | ||
297 | */ | ||
298 | void uwb_beca_purge(void) | ||
299 | { | ||
300 | struct uwb_beca_e *bce, *next; | ||
301 | unsigned long expires; | ||
302 | |||
303 | mutex_lock(&uwb_beca.mutex); | ||
304 | list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { | ||
305 | expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms); | ||
306 | if (time_after(jiffies, expires)) { | ||
307 | uwbd_dev_offair(bce); | ||
308 | list_del(&bce->node); | ||
309 | uwb_bce_put(bce); | ||
310 | } | ||
311 | } | ||
312 | mutex_unlock(&uwb_beca.mutex); | ||
313 | } | ||
314 | |||
315 | /* Clean up the whole beacon cache. Called on shutdown */ | ||
316 | void uwb_beca_release(void) | ||
317 | { | ||
318 | struct uwb_beca_e *bce, *next; | ||
319 | mutex_lock(&uwb_beca.mutex); | ||
320 | list_for_each_entry_safe(bce, next, &uwb_beca.list, node) { | ||
321 | list_del(&bce->node); | ||
322 | uwb_bce_put(bce); | ||
323 | } | ||
324 | mutex_unlock(&uwb_beca.mutex); | ||
325 | } | ||
326 | |||
327 | static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be, | ||
328 | struct uwb_beacon_frame *bf) | ||
329 | { | ||
330 | char macbuf[UWB_ADDR_STRSIZE]; | ||
331 | char devbuf[UWB_ADDR_STRSIZE]; | ||
332 | char dstbuf[UWB_ADDR_STRSIZE]; | ||
333 | |||
334 | uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier); | ||
335 | uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr); | ||
336 | uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr); | ||
337 | dev_info(&rc->uwb_dev.dev, | ||
338 | "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n", | ||
339 | devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset, | ||
340 | bf->Beacon_Slot_Number, macbuf); | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * @bce: beacon cache entry, referenced | ||
345 | */ | ||
346 | ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce, | ||
347 | char *buf, size_t size) | ||
348 | { | ||
349 | ssize_t result = 0; | ||
350 | struct uwb_rc_evt_beacon *be; | ||
351 | struct uwb_beacon_frame *bf; | ||
352 | struct uwb_buf_ctx ctx = { | ||
353 | .buf = buf, | ||
354 | .bytes = 0, | ||
355 | .size = size | ||
356 | }; | ||
357 | |||
358 | mutex_lock(&bce->mutex); | ||
359 | be = bce->be; | ||
360 | if (be == NULL) | ||
361 | goto out; | ||
362 | bf = (void *) be->BeaconInfo; | ||
363 | uwb_ie_for_each(uwb_dev, uwb_ie_dump_hex, &ctx, | ||
364 | bf->IEData, be->wBeaconInfoLength - sizeof(*bf)); | ||
365 | result = ctx.bytes; | ||
366 | out: | ||
367 | mutex_unlock(&bce->mutex); | ||
368 | return result; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Verify that the beacon event, frame and IEs are ok | ||
373 | */ | ||
374 | static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt, | ||
375 | struct uwb_rc_evt_beacon *be) | ||
376 | { | ||
377 | int result = -EINVAL; | ||
378 | struct uwb_beacon_frame *bf; | ||
379 | struct device *dev = &rc->uwb_dev.dev; | ||
380 | |||
381 | /* Is there enough data to decode a beacon frame? */ | ||
382 | if (evt->notif.size < sizeof(*be) + sizeof(*bf)) { | ||
383 | dev_err(dev, "BEACON event: Not enough data to decode " | ||
384 | "(%zu vs %zu bytes needed)\n", evt->notif.size, | ||
385 | sizeof(*be) + sizeof(*bf)); | ||
386 | goto error; | ||
387 | } | ||
388 | /* FIXME: make sure beacon frame IEs are fine and that the whole thing | ||
389 | * is consistent */ | ||
390 | result = 0; | ||
391 | error: | ||
392 | return result; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Handle UWB_RC_EVT_BEACON events | ||
397 | * | ||
398 | * We check the beacon cache to see how the received beacon fares. If | ||
399 | * is there already we refresh the timestamp. If not we create a new | ||
400 | * entry. | ||
401 | * | ||
402 | * According to the WHCI and WUSB specs, only one beacon frame is | ||
403 | * allowed per notification block, so we don't bother about scanning | ||
404 | * for more. | ||
405 | */ | ||
406 | int uwbd_evt_handle_rc_beacon(struct uwb_event *evt) | ||
407 | { | ||
408 | int result = -EINVAL; | ||
409 | struct uwb_rc *rc; | ||
410 | struct uwb_rc_evt_beacon *be; | ||
411 | struct uwb_beacon_frame *bf; | ||
412 | struct uwb_beca_e *bce; | ||
413 | unsigned long last_ts; | ||
414 | |||
415 | rc = evt->rc; | ||
416 | be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb); | ||
417 | result = uwb_verify_beacon(rc, evt, be); | ||
418 | if (result < 0) | ||
419 | return result; | ||
420 | |||
421 | /* FIXME: handle alien beacons. */ | ||
422 | if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN || | ||
423 | be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) { | ||
424 | return -ENOSYS; | ||
425 | } | ||
426 | |||
427 | bf = (struct uwb_beacon_frame *) be->BeaconInfo; | ||
428 | |||
429 | /* | ||
430 | * Drop beacons from devices with a NULL EUI-48 -- they cannot | ||
431 | * be uniquely identified. | ||
432 | * | ||
433 | * It's expected that these will all be WUSB devices and they | ||
434 | * have a WUSB specific connection method so ignoring them | ||
435 | * here shouldn't be a problem. | ||
436 | */ | ||
437 | if (uwb_mac_addr_bcast(&bf->Device_Identifier)) | ||
438 | return 0; | ||
439 | |||
440 | mutex_lock(&uwb_beca.mutex); | ||
441 | bce = __uwb_beca_find_bymac(&bf->Device_Identifier); | ||
442 | if (bce == NULL) { | ||
443 | /* Not in there, a new device is pinging */ | ||
444 | uwb_beacon_print(evt->rc, be, bf); | ||
445 | bce = __uwb_beca_add(be, bf, evt->ts_jiffies); | ||
446 | if (bce == NULL) { | ||
447 | mutex_unlock(&uwb_beca.mutex); | ||
448 | return -ENOMEM; | ||
449 | } | ||
450 | } | ||
451 | mutex_unlock(&uwb_beca.mutex); | ||
452 | |||
453 | mutex_lock(&bce->mutex); | ||
454 | /* purge old beacon data */ | ||
455 | kfree(bce->be); | ||
456 | |||
457 | last_ts = bce->ts_jiffies; | ||
458 | |||
459 | /* Update commonly used fields */ | ||
460 | bce->ts_jiffies = evt->ts_jiffies; | ||
461 | bce->be = be; | ||
462 | bce->dev_addr = bf->hdr.SrcAddr; | ||
463 | bce->mac_addr = &bf->Device_Identifier; | ||
464 | be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset); | ||
465 | be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength); | ||
466 | stats_add_sample(&bce->lqe_stats, be->bLQI - 7); | ||
467 | stats_add_sample(&bce->rssi_stats, be->bRSSI + 18); | ||
468 | |||
469 | /* | ||
470 | * This might be a beacon from a new device. | ||
471 | */ | ||
472 | if (bce->uwb_dev == NULL) | ||
473 | uwbd_dev_onair(evt->rc, bce); | ||
474 | |||
475 | mutex_unlock(&bce->mutex); | ||
476 | |||
477 | return 1; /* we keep the event data */ | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Handle UWB_RC_EVT_BEACON_SIZE events | ||
482 | * | ||
483 | * XXXXX | ||
484 | */ | ||
485 | int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt) | ||
486 | { | ||
487 | int result = -EINVAL; | ||
488 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
489 | struct uwb_rc_evt_beacon_size *bs; | ||
490 | |||
491 | /* Is there enough data to decode the event? */ | ||
492 | if (evt->notif.size < sizeof(*bs)) { | ||
493 | dev_err(dev, "BEACON SIZE notification: Not enough data to " | ||
494 | "decode (%zu vs %zu bytes needed)\n", | ||
495 | evt->notif.size, sizeof(*bs)); | ||
496 | goto error; | ||
497 | } | ||
498 | bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb); | ||
499 | if (0) | ||
500 | dev_info(dev, "Beacon size changed to %u bytes " | ||
501 | "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize)); | ||
502 | else { | ||
503 | /* temporary hack until we do something with this message... */ | ||
504 | static unsigned count; | ||
505 | if (++count % 1000 == 0) | ||
506 | dev_info(dev, "Beacon size changed %u times " | ||
507 | "(FIXME: action?)\n", count); | ||
508 | } | ||
509 | result = 0; | ||
510 | error: | ||
511 | return result; | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event | ||
516 | * @evt: the BP_SLOT_CHANGE notification from the radio controller | ||
517 | * | ||
518 | * If the event indicates that no beacon period slots were available | ||
519 | * then radio controller has transitioned to a non-beaconing state. | ||
520 | * Otherwise, simply save the current beacon slot. | ||
521 | */ | ||
522 | int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt) | ||
523 | { | ||
524 | struct uwb_rc *rc = evt->rc; | ||
525 | struct device *dev = &rc->uwb_dev.dev; | ||
526 | struct uwb_rc_evt_bp_slot_change *bpsc; | ||
527 | |||
528 | if (evt->notif.size < sizeof(*bpsc)) { | ||
529 | dev_err(dev, "BP SLOT CHANGE event: Not enough data\n"); | ||
530 | return -EINVAL; | ||
531 | } | ||
532 | bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb); | ||
533 | |||
534 | mutex_lock(&rc->uwb_dev.mutex); | ||
535 | if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) { | ||
536 | dev_info(dev, "stopped beaconing: No free slots in BP\n"); | ||
537 | rc->beaconing = -1; | ||
538 | } else | ||
539 | rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc); | ||
540 | mutex_unlock(&rc->uwb_dev.mutex); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * Handle UWB_RC_EVT_BPOIE_CHANGE events | ||
547 | * | ||
548 | * XXXXX | ||
549 | */ | ||
550 | struct uwb_ie_bpo { | ||
551 | struct uwb_ie_hdr hdr; | ||
552 | u8 bp_length; | ||
553 | u8 data[]; | ||
554 | } __attribute__((packed)); | ||
555 | |||
556 | int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt) | ||
557 | { | ||
558 | int result = -EINVAL; | ||
559 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
560 | struct uwb_rc_evt_bpoie_change *bpoiec; | ||
561 | struct uwb_ie_bpo *bpoie; | ||
562 | static unsigned count; /* FIXME: this is a temp hack */ | ||
563 | size_t iesize; | ||
564 | |||
565 | /* Is there enough data to decode it? */ | ||
566 | if (evt->notif.size < sizeof(*bpoiec)) { | ||
567 | dev_err(dev, "BPOIEC notification: Not enough data to " | ||
568 | "decode (%zu vs %zu bytes needed)\n", | ||
569 | evt->notif.size, sizeof(*bpoiec)); | ||
570 | goto error; | ||
571 | } | ||
572 | bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb); | ||
573 | iesize = le16_to_cpu(bpoiec->wBPOIELength); | ||
574 | if (iesize < sizeof(*bpoie)) { | ||
575 | dev_err(dev, "BPOIEC notification: Not enough IE data to " | ||
576 | "decode (%zu vs %zu bytes needed)\n", | ||
577 | iesize, sizeof(*bpoie)); | ||
578 | goto error; | ||
579 | } | ||
580 | if (++count % 1000 == 0) /* Lame placeholder */ | ||
581 | dev_info(dev, "BPOIE: %u changes received\n", count); | ||
582 | /* | ||
583 | * FIXME: At this point we should go over all the IEs in the | ||
584 | * bpoiec->BPOIE array and act on each. | ||
585 | */ | ||
586 | result = 0; | ||
587 | error: | ||
588 | return result; | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * uwb_bg_joined - is the RC in a beacon group? | ||
593 | * @rc: the radio controller | ||
594 | * | ||
595 | * Returns true if the radio controller is in a beacon group (even if | ||
596 | * it's the sole member). | ||
597 | */ | ||
598 | int uwb_bg_joined(struct uwb_rc *rc) | ||
599 | { | ||
600 | return rc->beaconing != -1; | ||
601 | } | ||
602 | EXPORT_SYMBOL_GPL(uwb_bg_joined); | ||
603 | |||
604 | /* | ||
605 | * Print beaconing state. | ||
606 | */ | ||
607 | static ssize_t uwb_rc_beacon_show(struct device *dev, | ||
608 | struct device_attribute *attr, char *buf) | ||
609 | { | ||
610 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
611 | struct uwb_rc *rc = uwb_dev->rc; | ||
612 | ssize_t result; | ||
613 | |||
614 | mutex_lock(&rc->uwb_dev.mutex); | ||
615 | result = sprintf(buf, "%d\n", rc->beaconing); | ||
616 | mutex_unlock(&rc->uwb_dev.mutex); | ||
617 | return result; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Start beaconing on the specified channel, or stop beaconing. | ||
622 | * | ||
623 | * The BPST offset of when to start searching for a beacon group to | ||
624 | * join may be specified. | ||
625 | */ | ||
626 | static ssize_t uwb_rc_beacon_store(struct device *dev, | ||
627 | struct device_attribute *attr, | ||
628 | const char *buf, size_t size) | ||
629 | { | ||
630 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
631 | struct uwb_rc *rc = uwb_dev->rc; | ||
632 | int channel; | ||
633 | unsigned bpst_offset = 0; | ||
634 | ssize_t result = -EINVAL; | ||
635 | |||
636 | result = sscanf(buf, "%d %u\n", &channel, &bpst_offset); | ||
637 | if (result >= 1) | ||
638 | result = uwb_rc_beacon(rc, channel, bpst_offset); | ||
639 | |||
640 | return result < 0 ? result : size; | ||
641 | } | ||
642 | DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store); | ||
diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c new file mode 100644 index 000000000000..521cdeb84971 --- /dev/null +++ b/drivers/uwb/driver.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Driver initialization, etc | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * Life cycle: FIXME: explain | ||
26 | * | ||
27 | * UWB radio controller: | ||
28 | * | ||
29 | * 1. alloc a uwb_rc, zero it | ||
30 | * 2. call uwb_rc_init() on it to set it up + ops (won't do any | ||
31 | * kind of allocation) | ||
32 | * 3. register (now it is owned by the UWB stack--deregister before | ||
33 | * freeing/destroying). | ||
34 | * 4. It lives on it's own now (UWB stack handles)--when it | ||
35 | * disconnects, call unregister() | ||
36 | * 5. free it. | ||
37 | * | ||
38 | * Make sure you have a reference to the uwb_rc before calling | ||
39 | * any of the UWB API functions. | ||
40 | * | ||
41 | * TODO: | ||
42 | * | ||
43 | * 1. Locking and life cycle management is crappy still. All entry | ||
44 | * points to the UWB HCD API assume you have a reference on the | ||
45 | * uwb_rc structure and that it won't go away. They mutex lock it | ||
46 | * before doing anything. | ||
47 | */ | ||
48 | |||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/init.h> | ||
51 | #include <linux/module.h> | ||
52 | #include <linux/device.h> | ||
53 | #include <linux/err.h> | ||
54 | #include <linux/kdev_t.h> | ||
55 | #include <linux/random.h> | ||
56 | #include <linux/uwb/debug.h> | ||
57 | #include "uwb-internal.h" | ||
58 | |||
59 | |||
60 | /* UWB stack attributes (or 'global' constants) */ | ||
61 | |||
62 | |||
63 | /** | ||
64 | * If a beacon dissapears for longer than this, then we consider the | ||
65 | * device who was represented by that beacon to be gone. | ||
66 | * | ||
67 | * ECMA-368[17.2.3, last para] establishes that a device must not | ||
68 | * consider a device to be its neighbour if he doesn't receive a beacon | ||
69 | * for more than mMaxLostBeacons. mMaxLostBeacons is defined in | ||
70 | * ECMA-368[17.16] as 3; because we can get only one beacon per | ||
71 | * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time | ||
72 | * for jitter and stuff and make it 500 ms. | ||
73 | */ | ||
74 | unsigned long beacon_timeout_ms = 500; | ||
75 | |||
76 | static | ||
77 | ssize_t beacon_timeout_ms_show(struct class *class, char *buf) | ||
78 | { | ||
79 | return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms); | ||
80 | } | ||
81 | |||
82 | static | ||
83 | ssize_t beacon_timeout_ms_store(struct class *class, | ||
84 | const char *buf, size_t size) | ||
85 | { | ||
86 | unsigned long bt; | ||
87 | ssize_t result; | ||
88 | result = sscanf(buf, "%lu", &bt); | ||
89 | if (result != 1) | ||
90 | return -EINVAL; | ||
91 | beacon_timeout_ms = bt; | ||
92 | return size; | ||
93 | } | ||
94 | |||
95 | static struct class_attribute uwb_class_attrs[] = { | ||
96 | __ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO, | ||
97 | beacon_timeout_ms_show, beacon_timeout_ms_store), | ||
98 | __ATTR_NULL, | ||
99 | }; | ||
100 | |||
101 | /** Device model classes */ | ||
102 | struct class uwb_rc_class = { | ||
103 | .name = "uwb_rc", | ||
104 | .class_attrs = uwb_class_attrs, | ||
105 | }; | ||
106 | |||
107 | |||
108 | static int __init uwb_subsys_init(void) | ||
109 | { | ||
110 | int result = 0; | ||
111 | |||
112 | result = uwb_est_create(); | ||
113 | if (result < 0) { | ||
114 | printk(KERN_ERR "uwb: Can't initialize EST subsystem\n"); | ||
115 | goto error_est_init; | ||
116 | } | ||
117 | |||
118 | result = class_register(&uwb_rc_class); | ||
119 | if (result < 0) | ||
120 | goto error_uwb_rc_class_register; | ||
121 | uwbd_start(); | ||
122 | uwb_dbg_init(); | ||
123 | return 0; | ||
124 | |||
125 | error_uwb_rc_class_register: | ||
126 | uwb_est_destroy(); | ||
127 | error_est_init: | ||
128 | return result; | ||
129 | } | ||
130 | module_init(uwb_subsys_init); | ||
131 | |||
132 | static void __exit uwb_subsys_exit(void) | ||
133 | { | ||
134 | uwb_dbg_exit(); | ||
135 | uwbd_stop(); | ||
136 | class_unregister(&uwb_rc_class); | ||
137 | uwb_est_destroy(); | ||
138 | return; | ||
139 | } | ||
140 | module_exit(uwb_subsys_exit); | ||
141 | |||
142 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
143 | MODULE_DESCRIPTION("Ultra Wide Band core"); | ||
144 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c new file mode 100644 index 000000000000..3febd8552808 --- /dev/null +++ b/drivers/uwb/drp-avail.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * DRP availability management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | * | ||
22 | * Manage DRP Availability (the MAS available for DRP | ||
23 | * reservations). Thus: | ||
24 | * | ||
25 | * - Handle DRP Availability Change notifications | ||
26 | * | ||
27 | * - Allow the reservation manager to indicate MAS reserved/released | ||
28 | * by local (owned by/targeted at the radio controller) | ||
29 | * reservations. | ||
30 | * | ||
31 | * - Based on the two sources above, generate a DRP Availability IE to | ||
32 | * be included in the beacon. | ||
33 | * | ||
34 | * See also the documentation for struct uwb_drp_avail. | ||
35 | */ | ||
36 | |||
37 | #include <linux/errno.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/device.h> | ||
40 | #include <linux/bitmap.h> | ||
41 | #include "uwb-internal.h" | ||
42 | |||
43 | /** | ||
44 | * uwb_drp_avail_init - initialize an RC's MAS availability | ||
45 | * | ||
46 | * All MAS are available initially. The RC will inform use which | ||
47 | * slots are used for the BP (it may change in size). | ||
48 | */ | ||
49 | void uwb_drp_avail_init(struct uwb_rc *rc) | ||
50 | { | ||
51 | bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS); | ||
52 | bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS); | ||
53 | bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Determine MAS available for new local reservations. | ||
58 | * | ||
59 | * avail = global & local & pending | ||
60 | */ | ||
61 | static void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) | ||
62 | { | ||
63 | bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
64 | bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation | ||
69 | * @rc: the radio controller | ||
70 | * @mas: the MAS to reserve | ||
71 | * | ||
72 | * Returns 0 on success, or -EBUSY if the MAS requested aren't available. | ||
73 | */ | ||
74 | int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
75 | { | ||
76 | struct uwb_mas_bm avail; | ||
77 | |||
78 | uwb_drp_available(rc, &avail); | ||
79 | if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS)) | ||
80 | return -EBUSY; | ||
81 | |||
82 | bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * uwb_drp_avail_reserve - reserve MAS for an established reservation | ||
88 | * @rc: the radio controller | ||
89 | * @mas: the MAS to reserve | ||
90 | */ | ||
91 | void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
92 | { | ||
93 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
94 | bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
95 | rc->drp_avail.ie_valid = false; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * uwb_drp_avail_release - release MAS from a pending or established reservation | ||
100 | * @rc: the radio controller | ||
101 | * @mas: the MAS to release | ||
102 | */ | ||
103 | void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
104 | { | ||
105 | bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
106 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
107 | rc->drp_avail.ie_valid = false; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * uwb_drp_avail_ie_update - update the DRP Availability IE | ||
112 | * @rc: the radio controller | ||
113 | * | ||
114 | * avail = global & local | ||
115 | */ | ||
116 | void uwb_drp_avail_ie_update(struct uwb_rc *rc) | ||
117 | { | ||
118 | struct uwb_mas_bm avail; | ||
119 | |||
120 | bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
121 | |||
122 | rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY; | ||
123 | rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8; | ||
124 | uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail); | ||
125 | rc->drp_avail.ie_valid = true; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Create an unsigned long from a buffer containing a byte stream. | ||
130 | * | ||
131 | * @array: pointer to buffer | ||
132 | * @itr: index of buffer from where we start | ||
133 | * @len: the buffer's remaining size may not be exact multiple of | ||
134 | * sizeof(unsigned long), @len is the length of buffer that needs | ||
135 | * to be converted. This will be sizeof(unsigned long) or smaller | ||
136 | * (BUG if not). If it is smaller then we will pad the remaining | ||
137 | * space of the result with zeroes. | ||
138 | */ | ||
139 | static | ||
140 | unsigned long get_val(u8 *array, size_t itr, size_t len) | ||
141 | { | ||
142 | unsigned long val = 0; | ||
143 | size_t top = itr + len; | ||
144 | |||
145 | BUG_ON(len > sizeof(val)); | ||
146 | |||
147 | while (itr < top) { | ||
148 | val <<= 8; | ||
149 | val |= array[top - 1]; | ||
150 | top--; | ||
151 | } | ||
152 | val <<= 8 * (sizeof(val) - len); /* padding */ | ||
153 | return val; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Initialize bitmap from data buffer. | ||
158 | * | ||
159 | * The bitmap to be converted could come from a IE, for example a | ||
160 | * DRP Availability IE. | ||
161 | * From ECMA-368 1.0 [16.8.7]: " | ||
162 | * octets: 1 1 N * (0 to 32) | ||
163 | * Element ID Length (=N) DRP Availability Bitmap | ||
164 | * | ||
165 | * The DRP Availability Bitmap field is up to 256 bits long, one | ||
166 | * bit for each MAS in the superframe, where the least-significant | ||
167 | * bit of the field corresponds to the first MAS in the superframe | ||
168 | * and successive bits correspond to successive MASs." | ||
169 | * | ||
170 | * The DRP Availability bitmap is in octets from 0 to 32, so octet | ||
171 | * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32 | ||
172 | * octets, the bits in octets not included at the end of the bitmap are | ||
173 | * treated as zero. In this case (when the bitmap is smaller than 32 | ||
174 | * octets) the MAS represented range from MAS 1 to MAS (size of bitmap) | ||
175 | * with the last octet still containing bits for MAS 1-8, etc. | ||
176 | * | ||
177 | * For example: | ||
178 | * F00F0102 03040506 0708090A 0B0C0D0E 0F010203 | ||
179 | * ^^^^ | ||
180 | * |||| | ||
181 | * |||| | ||
182 | * |||\LSB of byte is MAS 9 | ||
183 | * ||\MSB of byte is MAS 16 | ||
184 | * |\LSB of first byte is MAS 1 | ||
185 | * \ MSB of byte is MAS 8 | ||
186 | * | ||
187 | * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11] | ||
188 | * | ||
189 | * The resulting bitmap will have the following mapping: | ||
190 | * bit position 0 == MAS 1 | ||
191 | * bit position 1 == MAS 2 | ||
192 | * ... | ||
193 | * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS | ||
194 | * | ||
195 | * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP) | ||
196 | * @buffer: pointer to buffer containing bitmap data in big endian | ||
197 | * format (MSB first) | ||
198 | * @buffer_size:number of bytes with which bitmap should be initialized | ||
199 | */ | ||
200 | static | ||
201 | void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer, | ||
202 | size_t buffer_size) | ||
203 | { | ||
204 | u8 *buffer = _buffer; | ||
205 | size_t itr, len; | ||
206 | unsigned long val; | ||
207 | |||
208 | itr = 0; | ||
209 | while (itr < buffer_size) { | ||
210 | len = buffer_size - itr >= sizeof(val) ? | ||
211 | sizeof(val) : buffer_size - itr; | ||
212 | val = get_val(buffer, itr, len); | ||
213 | bmp_itr[itr / sizeof(val)] = val; | ||
214 | itr += sizeof(val); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Extract DRP Availability bitmap from the notification. | ||
221 | * | ||
222 | * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes | ||
223 | * We convert that to our internal representation. | ||
224 | */ | ||
225 | static | ||
226 | int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp) | ||
227 | { | ||
228 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
229 | struct uwb_rc_evt_drp_avail *drp_evt; | ||
230 | int result = -EINVAL; | ||
231 | |||
232 | /* Is there enough data to decode the event? */ | ||
233 | if (evt->notif.size < sizeof(*drp_evt)) { | ||
234 | dev_err(dev, "DRP Availability Change: Not enough " | ||
235 | "data to decode event [%zu bytes, %zu " | ||
236 | "needed]\n", evt->notif.size, sizeof(*drp_evt)); | ||
237 | goto error; | ||
238 | } | ||
239 | drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb); | ||
240 | buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8); | ||
241 | result = 0; | ||
242 | error: | ||
243 | return result; | ||
244 | } | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Process an incoming DRP Availability notification. | ||
249 | * | ||
250 | * @evt: Event information (packs the actual event data, which | ||
251 | * radio controller it came to, etc). | ||
252 | * | ||
253 | * @returns: 0 on success (so uwbd() frees the event buffer), < 0 | ||
254 | * on error. | ||
255 | * | ||
256 | * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that | ||
257 | * the MAS slot is available, bits set to ZERO indicate that the slot | ||
258 | * is busy. | ||
259 | * | ||
260 | * So we clear available slots, we set used slots :) | ||
261 | * | ||
262 | * The notification only marks non-availability based on the BP and | ||
263 | * received DRP IEs that are not for this radio controller. A copy of | ||
264 | * this bitmap is needed to generate the real availability (which | ||
265 | * includes local and pending reservations). | ||
266 | * | ||
267 | * The DRP Availability IE that this radio controller emits will need | ||
268 | * to be updated. | ||
269 | */ | ||
270 | int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt) | ||
271 | { | ||
272 | int result; | ||
273 | struct uwb_rc *rc = evt->rc; | ||
274 | DECLARE_BITMAP(bmp, UWB_NUM_MAS); | ||
275 | |||
276 | result = uwbd_evt_get_drp_avail(evt, bmp); | ||
277 | if (result < 0) | ||
278 | return result; | ||
279 | |||
280 | mutex_lock(&rc->rsvs_mutex); | ||
281 | bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS); | ||
282 | rc->drp_avail.ie_valid = false; | ||
283 | mutex_unlock(&rc->rsvs_mutex); | ||
284 | |||
285 | uwb_rsv_sched_update(rc); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c new file mode 100644 index 000000000000..882724c5f126 --- /dev/null +++ b/drivers/uwb/drp-ie.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * UWB DRP IE management. | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/random.h> | ||
22 | #include <linux/uwb.h> | ||
23 | |||
24 | #include "uwb-internal.h" | ||
25 | |||
26 | /* | ||
27 | * Allocate a DRP IE. | ||
28 | * | ||
29 | * To save having to free/allocate a DRP IE when its MAS changes, | ||
30 | * enough memory is allocated for the maxiumum number of DRP | ||
31 | * allocation fields. This gives an overhead per reservation of up to | ||
32 | * (UWB_NUM_ZONES - 1) * 4 = 60 octets. | ||
33 | */ | ||
34 | static struct uwb_ie_drp *uwb_drp_ie_alloc(void) | ||
35 | { | ||
36 | struct uwb_ie_drp *drp_ie; | ||
37 | unsigned tiebreaker; | ||
38 | |||
39 | drp_ie = kzalloc(sizeof(struct uwb_ie_drp) + | ||
40 | UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc), | ||
41 | GFP_KERNEL); | ||
42 | if (drp_ie) { | ||
43 | drp_ie->hdr.element_id = UWB_IE_DRP; | ||
44 | |||
45 | get_random_bytes(&tiebreaker, sizeof(unsigned)); | ||
46 | uwb_ie_drp_set_tiebreaker(drp_ie, tiebreaker & 1); | ||
47 | } | ||
48 | return drp_ie; | ||
49 | } | ||
50 | |||
51 | |||
52 | /* | ||
53 | * Fill a DRP IE's allocation fields from a MAS bitmap. | ||
54 | */ | ||
55 | static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie, | ||
56 | struct uwb_mas_bm *mas) | ||
57 | { | ||
58 | int z, i, num_fields = 0, next = 0; | ||
59 | struct uwb_drp_alloc *zones; | ||
60 | __le16 current_bmp; | ||
61 | DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS); | ||
62 | DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE); | ||
63 | |||
64 | zones = drp_ie->allocs; | ||
65 | |||
66 | bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS); | ||
67 | |||
68 | /* Determine unique MAS bitmaps in zones from bitmap. */ | ||
69 | for (z = 0; z < UWB_NUM_ZONES; z++) { | ||
70 | bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE); | ||
71 | if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) { | ||
72 | bool found = false; | ||
73 | current_bmp = (__le16) *tmp_mas_bm; | ||
74 | for (i = 0; i < next; i++) { | ||
75 | if (current_bmp == zones[i].mas_bm) { | ||
76 | zones[i].zone_bm |= 1 << z; | ||
77 | found = true; | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | if (!found) { | ||
82 | num_fields++; | ||
83 | zones[next].zone_bm = 1 << z; | ||
84 | zones[next].mas_bm = current_bmp; | ||
85 | next++; | ||
86 | } | ||
87 | } | ||
88 | bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
89 | } | ||
90 | |||
91 | /* Store in format ready for transmission (le16). */ | ||
92 | for (i = 0; i < num_fields; i++) { | ||
93 | drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm); | ||
94 | drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm); | ||
95 | } | ||
96 | |||
97 | drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr) | ||
98 | + num_fields * sizeof(struct uwb_drp_alloc); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * uwb_drp_ie_update - update a reservation's DRP IE | ||
103 | * @rsv: the reservation | ||
104 | */ | ||
105 | int uwb_drp_ie_update(struct uwb_rsv *rsv) | ||
106 | { | ||
107 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
108 | struct uwb_ie_drp *drp_ie; | ||
109 | int reason_code, status; | ||
110 | |||
111 | switch (rsv->state) { | ||
112 | case UWB_RSV_STATE_NONE: | ||
113 | kfree(rsv->drp_ie); | ||
114 | rsv->drp_ie = NULL; | ||
115 | return 0; | ||
116 | case UWB_RSV_STATE_O_INITIATED: | ||
117 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
118 | status = 0; | ||
119 | break; | ||
120 | case UWB_RSV_STATE_O_PENDING: | ||
121 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
122 | status = 0; | ||
123 | break; | ||
124 | case UWB_RSV_STATE_O_MODIFIED: | ||
125 | reason_code = UWB_DRP_REASON_MODIFIED; | ||
126 | status = 1; | ||
127 | break; | ||
128 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
129 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
130 | status = 1; | ||
131 | break; | ||
132 | case UWB_RSV_STATE_T_ACCEPTED: | ||
133 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
134 | status = 1; | ||
135 | break; | ||
136 | case UWB_RSV_STATE_T_DENIED: | ||
137 | reason_code = UWB_DRP_REASON_DENIED; | ||
138 | status = 0; | ||
139 | break; | ||
140 | default: | ||
141 | dev_dbg(dev, "rsv with unhandled state (%d)\n", rsv->state); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | if (rsv->drp_ie == NULL) { | ||
146 | rsv->drp_ie = uwb_drp_ie_alloc(); | ||
147 | if (rsv->drp_ie == NULL) | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | drp_ie = rsv->drp_ie; | ||
151 | |||
152 | uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv)); | ||
153 | uwb_ie_drp_set_status(drp_ie, status); | ||
154 | uwb_ie_drp_set_reason_code(drp_ie, reason_code); | ||
155 | uwb_ie_drp_set_stream_index(drp_ie, rsv->stream); | ||
156 | uwb_ie_drp_set_type(drp_ie, rsv->type); | ||
157 | |||
158 | if (uwb_rsv_is_owner(rsv)) { | ||
159 | switch (rsv->target.type) { | ||
160 | case UWB_RSV_TARGET_DEV: | ||
161 | drp_ie->dev_addr = rsv->target.dev->dev_addr; | ||
162 | break; | ||
163 | case UWB_RSV_TARGET_DEVADDR: | ||
164 | drp_ie->dev_addr = rsv->target.devaddr; | ||
165 | break; | ||
166 | } | ||
167 | } else | ||
168 | drp_ie->dev_addr = rsv->owner->dev_addr; | ||
169 | |||
170 | uwb_drp_ie_from_bm(drp_ie, &rsv->mas); | ||
171 | |||
172 | rsv->ie_valid = true; | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Set MAS bits from given MAS bitmap in a single zone of large bitmap. | ||
178 | * | ||
179 | * We are given a zone id and the MAS bitmap of bits that need to be set in | ||
180 | * this zone. Note that this zone may already have bits set and this only | ||
181 | * adds settings - we cannot simply assign the MAS bitmap contents to the | ||
182 | * zone contents. We iterate over the the bits (MAS) in the zone and set the | ||
183 | * bits that are set in the given MAS bitmap. | ||
184 | */ | ||
185 | static | ||
186 | void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm) | ||
187 | { | ||
188 | int mas; | ||
189 | u16 mas_mask; | ||
190 | |||
191 | for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) { | ||
192 | mas_mask = 1 << mas; | ||
193 | if (mas_bm & mas_mask) | ||
194 | set_bit(zone * UWB_NUM_ZONES + mas, bm->bm); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap | ||
200 | * @mas: MAS bitmap that will be populated to correspond to the | ||
201 | * allocation fields in the DRP IE | ||
202 | * @drp_ie: the DRP IE that contains the allocation fields. | ||
203 | * | ||
204 | * The input format is an array of MAS allocation fields (16 bit Zone | ||
205 | * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section | ||
206 | * 16.8.6. The output is a full 256 bit MAS bitmap. | ||
207 | * | ||
208 | * We go over all the allocation fields, for each allocation field we | ||
209 | * know which zones are impacted. We iterate over all the zones | ||
210 | * impacted and call a function that will set the correct MAS bits in | ||
211 | * each zone. | ||
212 | */ | ||
213 | void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie) | ||
214 | { | ||
215 | int numallocs = (drp_ie->hdr.length - 4) / 4; | ||
216 | const struct uwb_drp_alloc *alloc; | ||
217 | int cnt; | ||
218 | u16 zone_bm, mas_bm; | ||
219 | u8 zone; | ||
220 | u16 zone_mask; | ||
221 | |||
222 | for (cnt = 0; cnt < numallocs; cnt++) { | ||
223 | alloc = &drp_ie->allocs[cnt]; | ||
224 | zone_bm = le16_to_cpu(alloc->zone_bm); | ||
225 | mas_bm = le16_to_cpu(alloc->mas_bm); | ||
226 | for (zone = 0; zone < UWB_NUM_ZONES; zone++) { | ||
227 | zone_mask = 1 << zone; | ||
228 | if (zone_bm & zone_mask) | ||
229 | uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm); | ||
230 | } | ||
231 | } | ||
232 | } | ||
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c new file mode 100644 index 000000000000..c0b1e5e2bd08 --- /dev/null +++ b/drivers/uwb/drp.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Dynamic Reservation Protocol handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | #include <linux/kthread.h> | ||
22 | #include <linux/freezer.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include "uwb-internal.h" | ||
25 | |||
26 | /** | ||
27 | * Construct and send the SET DRP IE | ||
28 | * | ||
29 | * @rc: UWB Host controller | ||
30 | * @returns: >= 0 number of bytes still available in the beacon | ||
31 | * < 0 errno code on error. | ||
32 | * | ||
33 | * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the | ||
34 | * device to include in its beacon at the same time. We thus have to | ||
35 | * traverse all reservations and include the DRP IEs of all PENDING | ||
36 | * and NEGOTIATED reservations in a SET DRP command for transmission. | ||
37 | * | ||
38 | * A DRP Availability IE is appended. | ||
39 | * | ||
40 | * rc->uwb_dev.mutex is held | ||
41 | * | ||
42 | * FIXME We currently ignore the returned value indicating the remaining space | ||
43 | * in beacon. This could be used to deny reservation requests earlier if | ||
44 | * determined that they would cause the beacon space to be exceeded. | ||
45 | */ | ||
46 | static | ||
47 | int uwb_rc_gen_send_drp_ie(struct uwb_rc *rc) | ||
48 | { | ||
49 | int result; | ||
50 | struct device *dev = &rc->uwb_dev.dev; | ||
51 | struct uwb_rc_cmd_set_drp_ie *cmd; | ||
52 | struct uwb_rc_evt_set_drp_ie reply; | ||
53 | struct uwb_rsv *rsv; | ||
54 | int num_bytes = 0; | ||
55 | u8 *IEDataptr; | ||
56 | |||
57 | result = -ENOMEM; | ||
58 | /* First traverse all reservations to determine memory needed. */ | ||
59 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
60 | if (rsv->drp_ie != NULL) | ||
61 | num_bytes += rsv->drp_ie->hdr.length + 2; | ||
62 | } | ||
63 | num_bytes += sizeof(rc->drp_avail.ie); | ||
64 | cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL); | ||
65 | if (cmd == NULL) | ||
66 | goto error; | ||
67 | cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
68 | cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE); | ||
69 | cmd->wIELength = num_bytes; | ||
70 | IEDataptr = (u8 *)&cmd->IEData[0]; | ||
71 | |||
72 | /* Next traverse all reservations to place IEs in allocated memory. */ | ||
73 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
74 | if (rsv->drp_ie != NULL) { | ||
75 | memcpy(IEDataptr, rsv->drp_ie, | ||
76 | rsv->drp_ie->hdr.length + 2); | ||
77 | IEDataptr += rsv->drp_ie->hdr.length + 2; | ||
78 | } | ||
79 | } | ||
80 | memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie)); | ||
81 | |||
82 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
83 | reply.rceb.wEvent = UWB_RC_CMD_SET_DRP_IE; | ||
84 | result = uwb_rc_cmd(rc, "SET-DRP-IE", &cmd->rccb, | ||
85 | sizeof(*cmd) + num_bytes, &reply.rceb, | ||
86 | sizeof(reply)); | ||
87 | if (result < 0) | ||
88 | goto error_cmd; | ||
89 | result = le16_to_cpu(reply.wRemainingSpace); | ||
90 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
91 | dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: command execution " | ||
92 | "failed: %s (%d). RemainingSpace in beacon " | ||
93 | "= %d\n", uwb_rc_strerror(reply.bResultCode), | ||
94 | reply.bResultCode, result); | ||
95 | result = -EIO; | ||
96 | } else { | ||
97 | dev_dbg(dev, "SET-DRP-IE sent. RemainingSpace in beacon " | ||
98 | "= %d.\n", result); | ||
99 | result = 0; | ||
100 | } | ||
101 | error_cmd: | ||
102 | kfree(cmd); | ||
103 | error: | ||
104 | return result; | ||
105 | |||
106 | } | ||
107 | /** | ||
108 | * Send all DRP IEs associated with this host | ||
109 | * | ||
110 | * @returns: >= 0 number of bytes still available in the beacon | ||
111 | * < 0 errno code on error. | ||
112 | * | ||
113 | * As per the protocol we obtain the host controller device lock to access | ||
114 | * bandwidth structures. | ||
115 | */ | ||
116 | int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) | ||
117 | { | ||
118 | int result; | ||
119 | |||
120 | mutex_lock(&rc->uwb_dev.mutex); | ||
121 | result = uwb_rc_gen_send_drp_ie(rc); | ||
122 | mutex_unlock(&rc->uwb_dev.mutex); | ||
123 | return result; | ||
124 | } | ||
125 | |||
126 | void uwb_drp_handle_timeout(struct uwb_rsv *rsv) | ||
127 | { | ||
128 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
129 | |||
130 | dev_dbg(dev, "reservation timeout in state %s (%d)\n", | ||
131 | uwb_rsv_state_str(rsv->state), rsv->state); | ||
132 | |||
133 | switch (rsv->state) { | ||
134 | case UWB_RSV_STATE_O_INITIATED: | ||
135 | if (rsv->is_multicast) { | ||
136 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
137 | return; | ||
138 | } | ||
139 | break; | ||
140 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
141 | if (rsv->is_multicast) | ||
142 | return; | ||
143 | break; | ||
144 | default: | ||
145 | break; | ||
146 | } | ||
147 | uwb_rsv_remove(rsv); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Based on the DRP IE, transition a target reservation to a new | ||
152 | * state. | ||
153 | */ | ||
154 | static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv, | ||
155 | struct uwb_ie_drp *drp_ie) | ||
156 | { | ||
157 | struct device *dev = &rc->uwb_dev.dev; | ||
158 | int status; | ||
159 | enum uwb_drp_reason reason_code; | ||
160 | |||
161 | status = uwb_ie_drp_status(drp_ie); | ||
162 | reason_code = uwb_ie_drp_reason_code(drp_ie); | ||
163 | |||
164 | if (status) { | ||
165 | switch (reason_code) { | ||
166 | case UWB_DRP_REASON_ACCEPTED: | ||
167 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); | ||
168 | break; | ||
169 | case UWB_DRP_REASON_MODIFIED: | ||
170 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
171 | reason_code, status); | ||
172 | break; | ||
173 | default: | ||
174 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
175 | reason_code, status); | ||
176 | } | ||
177 | } else { | ||
178 | switch (reason_code) { | ||
179 | case UWB_DRP_REASON_ACCEPTED: | ||
180 | /* New reservations are handled in uwb_rsv_find(). */ | ||
181 | break; | ||
182 | case UWB_DRP_REASON_DENIED: | ||
183 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
184 | break; | ||
185 | case UWB_DRP_REASON_CONFLICT: | ||
186 | case UWB_DRP_REASON_MODIFIED: | ||
187 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
188 | reason_code, status); | ||
189 | break; | ||
190 | default: | ||
191 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
192 | reason_code, status); | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Based on the DRP IE, transition an owner reservation to a new | ||
199 | * state. | ||
200 | */ | ||
201 | static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, | ||
202 | struct uwb_ie_drp *drp_ie) | ||
203 | { | ||
204 | struct device *dev = &rc->uwb_dev.dev; | ||
205 | int status; | ||
206 | enum uwb_drp_reason reason_code; | ||
207 | |||
208 | status = uwb_ie_drp_status(drp_ie); | ||
209 | reason_code = uwb_ie_drp_reason_code(drp_ie); | ||
210 | |||
211 | if (status) { | ||
212 | switch (reason_code) { | ||
213 | case UWB_DRP_REASON_ACCEPTED: | ||
214 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
215 | break; | ||
216 | case UWB_DRP_REASON_MODIFIED: | ||
217 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
218 | reason_code, status); | ||
219 | break; | ||
220 | default: | ||
221 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
222 | reason_code, status); | ||
223 | } | ||
224 | } else { | ||
225 | switch (reason_code) { | ||
226 | case UWB_DRP_REASON_PENDING: | ||
227 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING); | ||
228 | break; | ||
229 | case UWB_DRP_REASON_DENIED: | ||
230 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
231 | break; | ||
232 | case UWB_DRP_REASON_CONFLICT: | ||
233 | case UWB_DRP_REASON_MODIFIED: | ||
234 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
235 | reason_code, status); | ||
236 | break; | ||
237 | default: | ||
238 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
239 | reason_code, status); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Process a received DRP IE, it's either for a reservation owned by | ||
246 | * the RC or targeted at it (or it's for a WUSB cluster reservation). | ||
247 | */ | ||
248 | static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src, | ||
249 | struct uwb_ie_drp *drp_ie) | ||
250 | { | ||
251 | struct uwb_rsv *rsv; | ||
252 | |||
253 | rsv = uwb_rsv_find(rc, src, drp_ie); | ||
254 | if (!rsv) { | ||
255 | /* | ||
256 | * No reservation? It's either for a recently | ||
257 | * terminated reservation; or the DRP IE couldn't be | ||
258 | * processed (e.g., an invalid IE or out of memory). | ||
259 | */ | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Do nothing with DRP IEs for reservations that have been | ||
265 | * terminated. | ||
266 | */ | ||
267 | if (rsv->state == UWB_RSV_STATE_NONE) { | ||
268 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | if (uwb_ie_drp_owner(drp_ie)) | ||
273 | uwb_drp_process_target(rc, rsv, drp_ie); | ||
274 | else | ||
275 | uwb_drp_process_owner(rc, rsv, drp_ie); | ||
276 | } | ||
277 | |||
278 | |||
279 | /* | ||
280 | * Process all the DRP IEs (both DRP IEs and the DRP Availability IE) | ||
281 | * from a device. | ||
282 | */ | ||
283 | static | ||
284 | void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, | ||
285 | size_t ielen, struct uwb_dev *src_dev) | ||
286 | { | ||
287 | struct device *dev = &rc->uwb_dev.dev; | ||
288 | struct uwb_ie_hdr *ie_hdr; | ||
289 | void *ptr; | ||
290 | |||
291 | ptr = drp_evt->ie_data; | ||
292 | for (;;) { | ||
293 | ie_hdr = uwb_ie_next(&ptr, &ielen); | ||
294 | if (!ie_hdr) | ||
295 | break; | ||
296 | |||
297 | switch (ie_hdr->element_id) { | ||
298 | case UWB_IE_DRP_AVAILABILITY: | ||
299 | /* FIXME: does something need to be done with this? */ | ||
300 | break; | ||
301 | case UWB_IE_DRP: | ||
302 | uwb_drp_process(rc, src_dev, (struct uwb_ie_drp *)ie_hdr); | ||
303 | break; | ||
304 | default: | ||
305 | dev_warn(dev, "unexpected IE in DRP notification\n"); | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | if (ielen > 0) | ||
311 | dev_warn(dev, "%d octets remaining in DRP notification\n", | ||
312 | (int)ielen); | ||
313 | } | ||
314 | |||
315 | |||
316 | /* | ||
317 | * Go through all the DRP IEs and find the ones that conflict with our | ||
318 | * reservations. | ||
319 | * | ||
320 | * FIXME: must resolve the conflict according the the rules in | ||
321 | * [ECMA-368]. | ||
322 | */ | ||
323 | static | ||
324 | void uwb_drp_process_conflict_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, | ||
325 | size_t ielen, struct uwb_dev *src_dev) | ||
326 | { | ||
327 | struct device *dev = &rc->uwb_dev.dev; | ||
328 | struct uwb_ie_hdr *ie_hdr; | ||
329 | struct uwb_ie_drp *drp_ie; | ||
330 | void *ptr; | ||
331 | |||
332 | ptr = drp_evt->ie_data; | ||
333 | for (;;) { | ||
334 | ie_hdr = uwb_ie_next(&ptr, &ielen); | ||
335 | if (!ie_hdr) | ||
336 | break; | ||
337 | |||
338 | drp_ie = container_of(ie_hdr, struct uwb_ie_drp, hdr); | ||
339 | |||
340 | /* FIXME: check if this DRP IE conflicts. */ | ||
341 | } | ||
342 | |||
343 | if (ielen > 0) | ||
344 | dev_warn(dev, "%d octets remaining in DRP notification\n", | ||
345 | (int)ielen); | ||
346 | } | ||
347 | |||
348 | |||
349 | /* | ||
350 | * Terminate all reservations owned by, or targeted at, 'uwb_dev'. | ||
351 | */ | ||
352 | static void uwb_drp_terminate_all(struct uwb_rc *rc, struct uwb_dev *uwb_dev) | ||
353 | { | ||
354 | struct uwb_rsv *rsv; | ||
355 | |||
356 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
357 | if (rsv->owner == uwb_dev | ||
358 | || (rsv->target.type == UWB_RSV_TARGET_DEV && rsv->target.dev == uwb_dev)) | ||
359 | uwb_rsv_remove(rsv); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * uwbd_evt_handle_rc_drp - handle a DRP_IE event | ||
366 | * @evt: the DRP_IE event from the radio controller | ||
367 | * | ||
368 | * This processes DRP notifications from the radio controller, either | ||
369 | * initiating a new reservation or transitioning an existing | ||
370 | * reservation into a different state. | ||
371 | * | ||
372 | * DRP notifications can occur for three different reasons: | ||
373 | * | ||
374 | * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as | ||
375 | * the target or source have been recieved. | ||
376 | * | ||
377 | * These DRP IEs could be new or for an existing reservation. | ||
378 | * | ||
379 | * If the DRP IE for an existing reservation ceases to be to | ||
380 | * recieved for at least mMaxLostBeacons, the reservation should be | ||
381 | * considered to be terminated. Note that the TERMINATE reason (see | ||
382 | * below) may not always be signalled (e.g., the remote device has | ||
383 | * two or more reservations established with the RC). | ||
384 | * | ||
385 | * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon | ||
386 | * group conflict with the RC's reservations. | ||
387 | * | ||
388 | * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received | ||
389 | * from a device (i.e., it's terminated all reservations). | ||
390 | * | ||
391 | * Only the software state of the reservations is changed; the setting | ||
392 | * of the radio controller's DRP IEs is done after all the events in | ||
393 | * an event buffer are processed. This saves waiting multiple times | ||
394 | * for the SET_DRP_IE command to complete. | ||
395 | */ | ||
396 | int uwbd_evt_handle_rc_drp(struct uwb_event *evt) | ||
397 | { | ||
398 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
399 | struct uwb_rc *rc = evt->rc; | ||
400 | struct uwb_rc_evt_drp *drp_evt; | ||
401 | size_t ielength, bytes_left; | ||
402 | struct uwb_dev_addr src_addr; | ||
403 | struct uwb_dev *src_dev; | ||
404 | int reason; | ||
405 | |||
406 | /* Is there enough data to decode the event (and any IEs in | ||
407 | its payload)? */ | ||
408 | if (evt->notif.size < sizeof(*drp_evt)) { | ||
409 | dev_err(dev, "DRP event: Not enough data to decode event " | ||
410 | "[%zu bytes left, %zu needed]\n", | ||
411 | evt->notif.size, sizeof(*drp_evt)); | ||
412 | return 0; | ||
413 | } | ||
414 | bytes_left = evt->notif.size - sizeof(*drp_evt); | ||
415 | drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb); | ||
416 | ielength = le16_to_cpu(drp_evt->ie_length); | ||
417 | if (bytes_left != ielength) { | ||
418 | dev_err(dev, "DRP event: Not enough data in payload [%zu" | ||
419 | "bytes left, %zu declared in the event]\n", | ||
420 | bytes_left, ielength); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr)); | ||
425 | src_dev = uwb_dev_get_by_devaddr(rc, &src_addr); | ||
426 | if (!src_dev) { | ||
427 | /* | ||
428 | * A DRP notification from an unrecognized device. | ||
429 | * | ||
430 | * This is probably from a WUSB device that doesn't | ||
431 | * have an EUI-48 and therefore doesn't show up in the | ||
432 | * UWB device database. It's safe to simply ignore | ||
433 | * these. | ||
434 | */ | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | mutex_lock(&rc->rsvs_mutex); | ||
439 | |||
440 | reason = uwb_rc_evt_drp_reason(drp_evt); | ||
441 | |||
442 | switch (reason) { | ||
443 | case UWB_DRP_NOTIF_DRP_IE_RCVD: | ||
444 | uwb_drp_process_all(rc, drp_evt, ielength, src_dev); | ||
445 | break; | ||
446 | case UWB_DRP_NOTIF_CONFLICT: | ||
447 | uwb_drp_process_conflict_all(rc, drp_evt, ielength, src_dev); | ||
448 | break; | ||
449 | case UWB_DRP_NOTIF_TERMINATE: | ||
450 | uwb_drp_terminate_all(rc, src_dev); | ||
451 | break; | ||
452 | default: | ||
453 | dev_warn(dev, "ignored DRP event with reason code: %d\n", reason); | ||
454 | break; | ||
455 | } | ||
456 | |||
457 | mutex_unlock(&rc->rsvs_mutex); | ||
458 | |||
459 | uwb_dev_put(src_dev); | ||
460 | return 0; | ||
461 | } | ||
diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c new file mode 100644 index 000000000000..5fe566b7c845 --- /dev/null +++ b/drivers/uwb/est.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band Radio Control | ||
3 | * Event Size Tables management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * Infrastructure, code and data tables for guessing the size of | ||
26 | * events received on the notification endpoints of UWB radio | ||
27 | * controllers. | ||
28 | * | ||
29 | * You define a table of events and for each, its size and how to get | ||
30 | * the extra size. | ||
31 | * | ||
32 | * ENTRY POINTS: | ||
33 | * | ||
34 | * uwb_est_{init/destroy}(): To initialize/release the EST subsystem. | ||
35 | * | ||
36 | * uwb_est_[u]register(): To un/register event size tables | ||
37 | * uwb_est_grow() | ||
38 | * | ||
39 | * uwb_est_find_size(): Get the size of an event | ||
40 | * uwb_est_get_size() | ||
41 | */ | ||
42 | #include <linux/spinlock.h> | ||
43 | #define D_LOCAL 0 | ||
44 | #include <linux/uwb/debug.h> | ||
45 | #include "uwb-internal.h" | ||
46 | |||
47 | |||
48 | struct uwb_est { | ||
49 | u16 type_event_high; | ||
50 | u16 vendor, product; | ||
51 | u8 entries; | ||
52 | const struct uwb_est_entry *entry; | ||
53 | }; | ||
54 | |||
55 | |||
56 | static struct uwb_est *uwb_est; | ||
57 | static u8 uwb_est_size; | ||
58 | static u8 uwb_est_used; | ||
59 | static DEFINE_RWLOCK(uwb_est_lock); | ||
60 | |||
61 | /** | ||
62 | * WUSB Standard Event Size Table, HWA-RC interface | ||
63 | * | ||
64 | * Sizes for events and notifications type 0 (general), high nibble 0. | ||
65 | */ | ||
66 | static | ||
67 | struct uwb_est_entry uwb_est_00_00xx[] = { | ||
68 | [UWB_RC_EVT_IE_RCV] = { | ||
69 | .size = sizeof(struct uwb_rc_evt_ie_rcv), | ||
70 | .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength), | ||
71 | }, | ||
72 | [UWB_RC_EVT_BEACON] = { | ||
73 | .size = sizeof(struct uwb_rc_evt_beacon), | ||
74 | .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength), | ||
75 | }, | ||
76 | [UWB_RC_EVT_BEACON_SIZE] = { | ||
77 | .size = sizeof(struct uwb_rc_evt_beacon_size), | ||
78 | }, | ||
79 | [UWB_RC_EVT_BPOIE_CHANGE] = { | ||
80 | .size = sizeof(struct uwb_rc_evt_bpoie_change), | ||
81 | .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change, | ||
82 | wBPOIELength), | ||
83 | }, | ||
84 | [UWB_RC_EVT_BP_SLOT_CHANGE] = { | ||
85 | .size = sizeof(struct uwb_rc_evt_bp_slot_change), | ||
86 | }, | ||
87 | [UWB_RC_EVT_BP_SWITCH_IE_RCV] = { | ||
88 | .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv), | ||
89 | .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength), | ||
90 | }, | ||
91 | [UWB_RC_EVT_DEV_ADDR_CONFLICT] = { | ||
92 | .size = sizeof(struct uwb_rc_evt_dev_addr_conflict), | ||
93 | }, | ||
94 | [UWB_RC_EVT_DRP_AVAIL] = { | ||
95 | .size = sizeof(struct uwb_rc_evt_drp_avail) | ||
96 | }, | ||
97 | [UWB_RC_EVT_DRP] = { | ||
98 | .size = sizeof(struct uwb_rc_evt_drp), | ||
99 | .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length), | ||
100 | }, | ||
101 | [UWB_RC_EVT_BP_SWITCH_STATUS] = { | ||
102 | .size = sizeof(struct uwb_rc_evt_bp_switch_status), | ||
103 | }, | ||
104 | [UWB_RC_EVT_CMD_FRAME_RCV] = { | ||
105 | .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv), | ||
106 | .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength), | ||
107 | }, | ||
108 | [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = { | ||
109 | .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv), | ||
110 | .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength), | ||
111 | }, | ||
112 | [UWB_RC_CMD_CHANNEL_CHANGE] = { | ||
113 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
114 | }, | ||
115 | [UWB_RC_CMD_DEV_ADDR_MGMT] = { | ||
116 | .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) }, | ||
117 | [UWB_RC_CMD_GET_IE] = { | ||
118 | .size = sizeof(struct uwb_rc_evt_get_ie), | ||
119 | .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength), | ||
120 | }, | ||
121 | [UWB_RC_CMD_RESET] = { | ||
122 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
123 | }, | ||
124 | [UWB_RC_CMD_SCAN] = { | ||
125 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
126 | }, | ||
127 | [UWB_RC_CMD_SET_BEACON_FILTER] = { | ||
128 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
129 | }, | ||
130 | [UWB_RC_CMD_SET_DRP_IE] = { | ||
131 | .size = sizeof(struct uwb_rc_evt_set_drp_ie), | ||
132 | }, | ||
133 | [UWB_RC_CMD_SET_IE] = { | ||
134 | .size = sizeof(struct uwb_rc_evt_set_ie), | ||
135 | }, | ||
136 | [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = { | ||
137 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
138 | }, | ||
139 | [UWB_RC_CMD_SET_TX_POWER] = { | ||
140 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
141 | }, | ||
142 | [UWB_RC_CMD_SLEEP] = { | ||
143 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
144 | }, | ||
145 | [UWB_RC_CMD_START_BEACON] = { | ||
146 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
147 | }, | ||
148 | [UWB_RC_CMD_STOP_BEACON] = { | ||
149 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
150 | }, | ||
151 | [UWB_RC_CMD_BP_MERGE] = { | ||
152 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
153 | }, | ||
154 | [UWB_RC_CMD_SEND_COMMAND_FRAME] = { | ||
155 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
156 | }, | ||
157 | [UWB_RC_CMD_SET_ASIE_NOTIF] = { | ||
158 | .size = sizeof(struct uwb_rc_evt_confirm), | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | static | ||
163 | struct uwb_est_entry uwb_est_01_00xx[] = { | ||
164 | [UWB_RC_DAA_ENERGY_DETECTED] = { | ||
165 | .size = sizeof(struct uwb_rc_evt_daa_energy_detected), | ||
166 | }, | ||
167 | [UWB_RC_SET_DAA_ENERGY_MASK] = { | ||
168 | .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask), | ||
169 | }, | ||
170 | [UWB_RC_SET_NOTIFICATION_FILTER_EX] = { | ||
171 | .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex), | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | /** | ||
176 | * Initialize the EST subsystem | ||
177 | * | ||
178 | * Register the standard tables also. | ||
179 | * | ||
180 | * FIXME: tag init | ||
181 | */ | ||
182 | int uwb_est_create(void) | ||
183 | { | ||
184 | int result; | ||
185 | |||
186 | uwb_est_size = 2; | ||
187 | uwb_est_used = 0; | ||
188 | uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL); | ||
189 | if (uwb_est == NULL) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff, | ||
193 | uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx)); | ||
194 | if (result < 0) | ||
195 | goto out; | ||
196 | result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff, | ||
197 | uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx)); | ||
198 | out: | ||
199 | return result; | ||
200 | } | ||
201 | |||
202 | |||
203 | /** Clean it up */ | ||
204 | void uwb_est_destroy(void) | ||
205 | { | ||
206 | kfree(uwb_est); | ||
207 | uwb_est = NULL; | ||
208 | uwb_est_size = uwb_est_used = 0; | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Double the capacity of the EST table | ||
214 | * | ||
215 | * @returns 0 if ok, < 0 errno no error. | ||
216 | */ | ||
217 | static | ||
218 | int uwb_est_grow(void) | ||
219 | { | ||
220 | size_t actual_size = uwb_est_size * sizeof(uwb_est[0]); | ||
221 | void *new = kmalloc(2 * actual_size, GFP_ATOMIC); | ||
222 | if (new == NULL) | ||
223 | return -ENOMEM; | ||
224 | memcpy(new, uwb_est, actual_size); | ||
225 | memset(new + actual_size, 0, actual_size); | ||
226 | kfree(uwb_est); | ||
227 | uwb_est = new; | ||
228 | uwb_est_size *= 2; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Register an event size table | ||
235 | * | ||
236 | * Makes room for it if the table is full, and then inserts it in the | ||
237 | * right position (entries are sorted by type, event_high, vendor and | ||
238 | * then product). | ||
239 | * | ||
240 | * @vendor: vendor code for matching against the device (0x0000 and | ||
241 | * 0xffff mean any); use 0x0000 to force all to match without | ||
242 | * checking possible vendor specific ones, 0xfffff to match | ||
243 | * after checking vendor specific ones. | ||
244 | * | ||
245 | * @product: product code from that vendor; same matching rules, use | ||
246 | * 0x0000 for not allowing vendor specific matches, 0xffff | ||
247 | * for allowing. | ||
248 | * | ||
249 | * This arragement just makes the tables sort differenty. Because the | ||
250 | * table is sorted by growing type-event_high-vendor-product, a zero | ||
251 | * vendor will match before than a 0x456a vendor, that will match | ||
252 | * before a 0xfffff vendor. | ||
253 | * | ||
254 | * @returns 0 if ok, < 0 errno on error (-ENOENT if not found). | ||
255 | */ | ||
256 | /* FIXME: add bus type to vendor/product code */ | ||
257 | int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product, | ||
258 | const struct uwb_est_entry *entry, size_t entries) | ||
259 | { | ||
260 | unsigned long flags; | ||
261 | unsigned itr; | ||
262 | u16 type_event_high; | ||
263 | int result = 0; | ||
264 | |||
265 | write_lock_irqsave(&uwb_est_lock, flags); | ||
266 | if (uwb_est_used == uwb_est_size) { | ||
267 | result = uwb_est_grow(); | ||
268 | if (result < 0) | ||
269 | goto out; | ||
270 | } | ||
271 | /* Find the right spot to insert it in */ | ||
272 | type_event_high = type << 8 | event_high; | ||
273 | for (itr = 0; itr < uwb_est_used; itr++) | ||
274 | if (uwb_est[itr].type_event_high < type | ||
275 | && uwb_est[itr].vendor < vendor | ||
276 | && uwb_est[itr].product < product) | ||
277 | break; | ||
278 | |||
279 | /* Shift others to make room for the new one? */ | ||
280 | if (itr < uwb_est_used) | ||
281 | memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr); | ||
282 | uwb_est[itr].type_event_high = type << 8 | event_high; | ||
283 | uwb_est[itr].vendor = vendor; | ||
284 | uwb_est[itr].product = product; | ||
285 | uwb_est[itr].entry = entry; | ||
286 | uwb_est[itr].entries = entries; | ||
287 | uwb_est_used++; | ||
288 | out: | ||
289 | write_unlock_irqrestore(&uwb_est_lock, flags); | ||
290 | return result; | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(uwb_est_register); | ||
293 | |||
294 | |||
295 | /** | ||
296 | * Unregister an event size table | ||
297 | * | ||
298 | * This just removes the specified entry and moves the ones after it | ||
299 | * to fill in the gap. This is needed to keep the list sorted; no | ||
300 | * reallocation is done to reduce the size of the table. | ||
301 | * | ||
302 | * We unregister by all the data we used to register instead of by | ||
303 | * pointer to the @entry array because we might have used the same | ||
304 | * table for a bunch of IDs (for example). | ||
305 | * | ||
306 | * @returns 0 if ok, < 0 errno on error (-ENOENT if not found). | ||
307 | */ | ||
308 | int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product, | ||
309 | const struct uwb_est_entry *entry, size_t entries) | ||
310 | { | ||
311 | unsigned long flags; | ||
312 | unsigned itr; | ||
313 | struct uwb_est est_cmp = { | ||
314 | .type_event_high = type << 8 | event_high, | ||
315 | .vendor = vendor, | ||
316 | .product = product, | ||
317 | .entry = entry, | ||
318 | .entries = entries | ||
319 | }; | ||
320 | write_lock_irqsave(&uwb_est_lock, flags); | ||
321 | for (itr = 0; itr < uwb_est_used; itr++) | ||
322 | if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp))) | ||
323 | goto found; | ||
324 | write_unlock_irqrestore(&uwb_est_lock, flags); | ||
325 | return -ENOENT; | ||
326 | |||
327 | found: | ||
328 | if (itr < uwb_est_used - 1) /* Not last one? move ones above */ | ||
329 | memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1); | ||
330 | uwb_est_used--; | ||
331 | write_unlock_irqrestore(&uwb_est_lock, flags); | ||
332 | return 0; | ||
333 | } | ||
334 | EXPORT_SYMBOL_GPL(uwb_est_unregister); | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Get the size of an event from a table | ||
339 | * | ||
340 | * @rceb: pointer to the buffer with the event | ||
341 | * @rceb_size: size of the area pointed to by @rceb in bytes. | ||
342 | * @returns: > 0 Size of the event | ||
343 | * -ENOSPC An area big enough was not provided to look | ||
344 | * ahead into the event's guts and guess the size. | ||
345 | * -EINVAL Unknown event code (wEvent). | ||
346 | * | ||
347 | * This will look at the received RCEB and guess what is the total | ||
348 | * size. For variable sized events, it will look further ahead into | ||
349 | * their length field to see how much data should be read. | ||
350 | * | ||
351 | * Note this size is *not* final--the neh (Notification/Event Handle) | ||
352 | * might specificy an extra size to add. | ||
353 | */ | ||
354 | static | ||
355 | ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est, | ||
356 | u8 event_low, const struct uwb_rceb *rceb, | ||
357 | size_t rceb_size) | ||
358 | { | ||
359 | unsigned offset; | ||
360 | ssize_t size; | ||
361 | struct device *dev = &uwb_rc->uwb_dev.dev; | ||
362 | const struct uwb_est_entry *entry; | ||
363 | |||
364 | size = -ENOENT; | ||
365 | if (event_low >= est->entries) { /* in range? */ | ||
366 | dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n", | ||
367 | est, est->type_event_high, est->vendor, est->product, | ||
368 | est->entries, event_low); | ||
369 | goto out; | ||
370 | } | ||
371 | size = -ENOENT; | ||
372 | entry = &est->entry[event_low]; | ||
373 | if (entry->size == 0 && entry->offset == 0) { /* unknown? */ | ||
374 | dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n", | ||
375 | est, est->type_event_high, est->vendor, est->product, | ||
376 | est->entries, event_low); | ||
377 | goto out; | ||
378 | } | ||
379 | offset = entry->offset; /* extra fries with that? */ | ||
380 | if (offset == 0) | ||
381 | size = entry->size; | ||
382 | else { | ||
383 | /* Ops, got an extra size field at 'offset'--read it */ | ||
384 | const void *ptr = rceb; | ||
385 | size_t type_size = 0; | ||
386 | offset--; | ||
387 | size = -ENOSPC; /* enough data for more? */ | ||
388 | switch (entry->type) { | ||
389 | case UWB_EST_16: type_size = sizeof(__le16); break; | ||
390 | case UWB_EST_8: type_size = sizeof(u8); break; | ||
391 | default: BUG(); | ||
392 | } | ||
393 | if (offset + type_size > rceb_size) { | ||
394 | dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: " | ||
395 | "not enough data to read extra size\n", | ||
396 | est, est->type_event_high, est->vendor, | ||
397 | est->product, est->entries); | ||
398 | goto out; | ||
399 | } | ||
400 | size = entry->size; | ||
401 | ptr += offset; | ||
402 | switch (entry->type) { | ||
403 | case UWB_EST_16: size += le16_to_cpu(*(__le16 *)ptr); break; | ||
404 | case UWB_EST_8: size += *(u8 *)ptr; break; | ||
405 | default: BUG(); | ||
406 | } | ||
407 | } | ||
408 | out: | ||
409 | return size; | ||
410 | } | ||
411 | |||
412 | |||
413 | /** | ||
414 | * Guesses the size of a WA event | ||
415 | * | ||
416 | * @rceb: pointer to the buffer with the event | ||
417 | * @rceb_size: size of the area pointed to by @rceb in bytes. | ||
418 | * @returns: > 0 Size of the event | ||
419 | * -ENOSPC An area big enough was not provided to look | ||
420 | * ahead into the event's guts and guess the size. | ||
421 | * -EINVAL Unknown event code (wEvent). | ||
422 | * | ||
423 | * This will look at the received RCEB and guess what is the total | ||
424 | * size by checking all the tables registered with | ||
425 | * uwb_est_register(). For variable sized events, it will look further | ||
426 | * ahead into their length field to see how much data should be read. | ||
427 | * | ||
428 | * Note this size is *not* final--the neh (Notification/Event Handle) | ||
429 | * might specificy an extra size to add or replace. | ||
430 | */ | ||
431 | ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, | ||
432 | size_t rceb_size) | ||
433 | { | ||
434 | /* FIXME: add vendor/product data */ | ||
435 | ssize_t size; | ||
436 | struct device *dev = &rc->uwb_dev.dev; | ||
437 | unsigned long flags; | ||
438 | unsigned itr; | ||
439 | u16 type_event_high, event; | ||
440 | u8 *ptr = (u8 *) rceb; | ||
441 | |||
442 | read_lock_irqsave(&uwb_est_lock, flags); | ||
443 | d_printf(2, dev, "Size query for event 0x%02x/%04x/%02x," | ||
444 | " buffer size %ld\n", | ||
445 | (unsigned) rceb->bEventType, | ||
446 | (unsigned) le16_to_cpu(rceb->wEvent), | ||
447 | (unsigned) rceb->bEventContext, | ||
448 | (long) rceb_size); | ||
449 | size = -ENOSPC; | ||
450 | if (rceb_size < sizeof(*rceb)) | ||
451 | goto out; | ||
452 | event = le16_to_cpu(rceb->wEvent); | ||
453 | type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8; | ||
454 | for (itr = 0; itr < uwb_est_used; itr++) { | ||
455 | d_printf(3, dev, "Checking EST 0x%04x/%04x/%04x\n", | ||
456 | uwb_est[itr].type_event_high, uwb_est[itr].vendor, | ||
457 | uwb_est[itr].product); | ||
458 | if (uwb_est[itr].type_event_high != type_event_high) | ||
459 | continue; | ||
460 | size = uwb_est_get_size(rc, &uwb_est[itr], | ||
461 | event & 0x00ff, rceb, rceb_size); | ||
462 | /* try more tables that might handle the same type */ | ||
463 | if (size != -ENOENT) | ||
464 | goto out; | ||
465 | } | ||
466 | dev_dbg(dev, "event 0x%02x/%04x/%02x: no handlers available; " | ||
467 | "RCEB %02x %02x %02x %02x\n", | ||
468 | (unsigned) rceb->bEventType, | ||
469 | (unsigned) le16_to_cpu(rceb->wEvent), | ||
470 | (unsigned) rceb->bEventContext, | ||
471 | ptr[0], ptr[1], ptr[2], ptr[3]); | ||
472 | size = -ENOENT; | ||
473 | out: | ||
474 | read_unlock_irqrestore(&uwb_est_lock, flags); | ||
475 | return size; | ||
476 | } | ||
477 | EXPORT_SYMBOL_GPL(uwb_est_find_size); | ||
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c new file mode 100644 index 000000000000..3d26fa0f8ae1 --- /dev/null +++ b/drivers/uwb/hwa-rc.c | |||
@@ -0,0 +1,926 @@ | |||
1 | /* | ||
2 | * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6]) | ||
3 | * Radio Control command/event transport | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Initialize the Radio Control interface Driver. | ||
24 | * | ||
25 | * For each device probed, creates an 'struct hwarc' which contains | ||
26 | * just the representation of the UWB Radio Controller, and the logic | ||
27 | * for reading notifications and passing them to the UWB Core. | ||
28 | * | ||
29 | * So we initialize all of those, register the UWB Radio Controller | ||
30 | * and setup the notification/event handle to pipe the notifications | ||
31 | * to the UWB management Daemon. | ||
32 | * | ||
33 | * Command and event filtering. | ||
34 | * | ||
35 | * This is the driver for the Radio Control Interface described in WUSB | ||
36 | * 1.0. The core UWB module assumes that all drivers are compliant to the | ||
37 | * WHCI 0.95 specification. We thus create a filter that parses all | ||
38 | * incoming messages from the (WUSB 1.0) device and manipulate them to | ||
39 | * conform to the WHCI 0.95 specification. Similarly, outgoing messages | ||
40 | * are parsed and manipulated to conform to the WUSB 1.0 compliant messages | ||
41 | * that the device expects. Only a few messages are affected: | ||
42 | * Affected events: | ||
43 | * UWB_RC_EVT_BEACON | ||
44 | * UWB_RC_EVT_BP_SLOT_CHANGE | ||
45 | * UWB_RC_EVT_DRP_AVAIL | ||
46 | * UWB_RC_EVT_DRP | ||
47 | * Affected commands: | ||
48 | * UWB_RC_CMD_SCAN | ||
49 | * UWB_RC_CMD_SET_DRP_IE | ||
50 | * | ||
51 | * | ||
52 | * | ||
53 | */ | ||
54 | #include <linux/version.h> | ||
55 | #include <linux/init.h> | ||
56 | #include <linux/module.h> | ||
57 | #include <linux/usb.h> | ||
58 | #include <linux/usb/wusb.h> | ||
59 | #include <linux/usb/wusb-wa.h> | ||
60 | #include <linux/uwb.h> | ||
61 | #include "uwb-internal.h" | ||
62 | #define D_LOCAL 1 | ||
63 | #include <linux/uwb/debug.h> | ||
64 | |||
65 | /* The device uses commands and events from the WHCI specification, although | ||
66 | * reporting itself as WUSB compliant. */ | ||
67 | #define WUSB_QUIRK_WHCI_CMD_EVT 0x01 | ||
68 | |||
69 | /** | ||
70 | * Descriptor for an instance of the UWB Radio Control Driver that | ||
71 | * attaches to the RCI interface of the Host Wired Adapter. | ||
72 | * | ||
73 | * Unless there is a lock specific to the 'data members', all access | ||
74 | * is protected by uwb_rc->mutex. | ||
75 | * | ||
76 | * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to | ||
77 | * @rd_buffer. Note there is no locking because it is perfectly (heh!) | ||
78 | * serialized--probe() submits an URB, callback is called, processes | ||
79 | * the data (synchronously), submits another URB, and so on. There is | ||
80 | * no concurrent access to the buffer. | ||
81 | */ | ||
82 | struct hwarc { | ||
83 | struct usb_device *usb_dev; | ||
84 | struct usb_interface *usb_iface; | ||
85 | struct uwb_rc *uwb_rc; /* UWB host controller */ | ||
86 | struct urb *neep_urb; /* Notification endpoint handling */ | ||
87 | struct edc neep_edc; | ||
88 | void *rd_buffer; /* NEEP read buffer */ | ||
89 | }; | ||
90 | |||
91 | |||
92 | /* Beacon received notification (WUSB 1.0 [8.6.3.2]) */ | ||
93 | struct uwb_rc_evt_beacon_WUSB_0100 { | ||
94 | struct uwb_rceb rceb; | ||
95 | u8 bChannelNumber; | ||
96 | __le16 wBPSTOffset; | ||
97 | u8 bLQI; | ||
98 | u8 bRSSI; | ||
99 | __le16 wBeaconInfoLength; | ||
100 | u8 BeaconInfo[]; | ||
101 | } __attribute__((packed)); | ||
102 | |||
103 | /** | ||
104 | * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95 | ||
105 | * | ||
106 | * @header: the incoming event | ||
107 | * @buf_size: size of buffer containing incoming event | ||
108 | * @new_size: size of event after filtering completed | ||
109 | * | ||
110 | * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at | ||
111 | * the time we receive the beacon from WUSB so we just set it to | ||
112 | * UWB_RC_BEACON_TYPE_NEIGHBOR as a default. | ||
113 | * The solution below allocates memory upon receipt of every beacon from a | ||
114 | * WUSB device. This will deteriorate performance. What is the right way to | ||
115 | * do this? | ||
116 | */ | ||
117 | static | ||
118 | int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc, | ||
119 | struct uwb_rceb **header, | ||
120 | const size_t buf_size, | ||
121 | size_t *new_size) | ||
122 | { | ||
123 | struct uwb_rc_evt_beacon_WUSB_0100 *be; | ||
124 | struct uwb_rc_evt_beacon *newbe; | ||
125 | size_t bytes_left, ielength; | ||
126 | struct device *dev = &rc->uwb_dev.dev; | ||
127 | |||
128 | be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb); | ||
129 | bytes_left = buf_size; | ||
130 | if (bytes_left < sizeof(*be)) { | ||
131 | dev_err(dev, "Beacon Received Notification: Not enough data " | ||
132 | "to decode for filtering (%zu vs %zu bytes needed)\n", | ||
133 | bytes_left, sizeof(*be)); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | bytes_left -= sizeof(*be); | ||
137 | ielength = le16_to_cpu(be->wBeaconInfoLength); | ||
138 | if (bytes_left < ielength) { | ||
139 | dev_err(dev, "Beacon Received Notification: Not enough data " | ||
140 | "to decode IEs (%zu vs %zu bytes needed)\n", | ||
141 | bytes_left, ielength); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC); | ||
145 | if (newbe == NULL) | ||
146 | return -ENOMEM; | ||
147 | newbe->rceb = be->rceb; | ||
148 | newbe->bChannelNumber = be->bChannelNumber; | ||
149 | newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR; | ||
150 | newbe->wBPSTOffset = be->wBPSTOffset; | ||
151 | newbe->bLQI = be->bLQI; | ||
152 | newbe->bRSSI = be->bRSSI; | ||
153 | newbe->wBeaconInfoLength = be->wBeaconInfoLength; | ||
154 | memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength); | ||
155 | *header = &newbe->rceb; | ||
156 | *new_size = sizeof(*newbe) + ielength; | ||
157 | return 1; /* calling function will free memory */ | ||
158 | } | ||
159 | |||
160 | |||
161 | /* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */ | ||
162 | struct uwb_rc_evt_drp_avail_WUSB_0100 { | ||
163 | struct uwb_rceb rceb; | ||
164 | __le16 wIELength; | ||
165 | u8 IEData[]; | ||
166 | } __attribute__((packed)); | ||
167 | |||
168 | /** | ||
169 | * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95 | ||
170 | * | ||
171 | * @header: the incoming event | ||
172 | * @buf_size: size of buffer containing incoming event | ||
173 | * @new_size: size of event after filtering completed | ||
174 | */ | ||
175 | static | ||
176 | int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc, | ||
177 | struct uwb_rceb **header, | ||
178 | const size_t buf_size, | ||
179 | size_t *new_size) | ||
180 | { | ||
181 | struct uwb_rc_evt_drp_avail_WUSB_0100 *da; | ||
182 | struct uwb_rc_evt_drp_avail *newda; | ||
183 | struct uwb_ie_hdr *ie_hdr; | ||
184 | size_t bytes_left, ielength; | ||
185 | struct device *dev = &rc->uwb_dev.dev; | ||
186 | |||
187 | |||
188 | da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb); | ||
189 | bytes_left = buf_size; | ||
190 | if (bytes_left < sizeof(*da)) { | ||
191 | dev_err(dev, "Not enough data to decode DRP Avail " | ||
192 | "Notification for filtering. Expected %zu, " | ||
193 | "received %zu.\n", (size_t)sizeof(*da), bytes_left); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | bytes_left -= sizeof(*da); | ||
197 | ielength = le16_to_cpu(da->wIELength); | ||
198 | if (bytes_left < ielength) { | ||
199 | dev_err(dev, "DRP Avail Notification filter: IE length " | ||
200 | "[%zu bytes] does not match actual length " | ||
201 | "[%zu bytes].\n", ielength, bytes_left); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | if (ielength < sizeof(*ie_hdr)) { | ||
205 | dev_err(dev, "DRP Avail Notification filter: Not enough " | ||
206 | "data to decode IE [%zu bytes, %zu needed]\n", | ||
207 | ielength, sizeof(*ie_hdr)); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | ie_hdr = (void *) da->IEData; | ||
211 | if (ie_hdr->length > 32) { | ||
212 | dev_err(dev, "DRP Availability Change event has unexpected " | ||
213 | "length for filtering. Expected < 32 bytes, " | ||
214 | "got %zu bytes.\n", (size_t)ie_hdr->length); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | newda = kzalloc(sizeof(*newda), GFP_ATOMIC); | ||
218 | if (newda == NULL) | ||
219 | return -ENOMEM; | ||
220 | newda->rceb = da->rceb; | ||
221 | memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length); | ||
222 | *header = &newda->rceb; | ||
223 | *new_size = sizeof(*newda); | ||
224 | return 1; /* calling function will free memory */ | ||
225 | } | ||
226 | |||
227 | |||
228 | /* DRP notification (WUSB 1.0 [8.6.3.9]) */ | ||
229 | struct uwb_rc_evt_drp_WUSB_0100 { | ||
230 | struct uwb_rceb rceb; | ||
231 | struct uwb_dev_addr wSrcAddr; | ||
232 | u8 bExplicit; | ||
233 | __le16 wIELength; | ||
234 | u8 IEData[]; | ||
235 | } __attribute__((packed)); | ||
236 | |||
237 | /** | ||
238 | * Filter WUSB 1.0 DRP Notification to be WHCI 0.95 | ||
239 | * | ||
240 | * @header: the incoming event | ||
241 | * @buf_size: size of buffer containing incoming event | ||
242 | * @new_size: size of event after filtering completed | ||
243 | * | ||
244 | * It is hard to manage DRP reservations without having a Reason code. | ||
245 | * Unfortunately there is none in the WUSB spec. We just set the default to | ||
246 | * DRP IE RECEIVED. | ||
247 | * We do not currently use the bBeaconSlotNumber value, so we set this to | ||
248 | * zero for now. | ||
249 | */ | ||
250 | static | ||
251 | int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc, | ||
252 | struct uwb_rceb **header, | ||
253 | const size_t buf_size, | ||
254 | size_t *new_size) | ||
255 | { | ||
256 | struct uwb_rc_evt_drp_WUSB_0100 *drpev; | ||
257 | struct uwb_rc_evt_drp *newdrpev; | ||
258 | size_t bytes_left, ielength; | ||
259 | struct device *dev = &rc->uwb_dev.dev; | ||
260 | |||
261 | drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb); | ||
262 | bytes_left = buf_size; | ||
263 | if (bytes_left < sizeof(*drpev)) { | ||
264 | dev_err(dev, "Not enough data to decode DRP Notification " | ||
265 | "for filtering. Expected %zu, received %zu.\n", | ||
266 | (size_t)sizeof(*drpev), bytes_left); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | ielength = le16_to_cpu(drpev->wIELength); | ||
270 | bytes_left -= sizeof(*drpev); | ||
271 | if (bytes_left < ielength) { | ||
272 | dev_err(dev, "DRP Notification filter: header length [%zu " | ||
273 | "bytes] does not match actual length [%zu " | ||
274 | "bytes].\n", ielength, bytes_left); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC); | ||
278 | if (newdrpev == NULL) | ||
279 | return -ENOMEM; | ||
280 | newdrpev->rceb = drpev->rceb; | ||
281 | newdrpev->src_addr = drpev->wSrcAddr; | ||
282 | newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD; | ||
283 | newdrpev->beacon_slot_number = 0; | ||
284 | newdrpev->ie_length = drpev->wIELength; | ||
285 | memcpy(newdrpev->ie_data, drpev->IEData, ielength); | ||
286 | *header = &newdrpev->rceb; | ||
287 | *new_size = sizeof(*newdrpev) + ielength; | ||
288 | return 1; /* calling function will free memory */ | ||
289 | } | ||
290 | |||
291 | |||
292 | /* Scan Command (WUSB 1.0 [8.6.2.5]) */ | ||
293 | struct uwb_rc_cmd_scan_WUSB_0100 { | ||
294 | struct uwb_rccb rccb; | ||
295 | u8 bChannelNumber; | ||
296 | u8 bScanState; | ||
297 | } __attribute__((packed)); | ||
298 | |||
299 | /** | ||
300 | * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command | ||
301 | * | ||
302 | * @header: command sent to device (compliant to WHCI 0.95) | ||
303 | * @size: size of command sent to device | ||
304 | * | ||
305 | * We only reduce the size by two bytes because the WUSB 1.0 scan command | ||
306 | * does not have the last field (wStarttime). Also, make sure we don't send | ||
307 | * the device an unexpected scan type. | ||
308 | */ | ||
309 | static | ||
310 | int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc, | ||
311 | struct uwb_rccb **header, | ||
312 | size_t *size) | ||
313 | { | ||
314 | struct uwb_rc_cmd_scan *sc; | ||
315 | |||
316 | sc = container_of(*header, struct uwb_rc_cmd_scan, rccb); | ||
317 | |||
318 | if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME) | ||
319 | sc->bScanState = UWB_SCAN_ONLY; | ||
320 | /* Don't send the last two bytes. */ | ||
321 | *size -= 2; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | |||
326 | /* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */ | ||
327 | struct uwb_rc_cmd_set_drp_ie_WUSB_0100 { | ||
328 | struct uwb_rccb rccb; | ||
329 | u8 bExplicit; | ||
330 | __le16 wIELength; | ||
331 | struct uwb_ie_drp IEData[]; | ||
332 | } __attribute__((packed)); | ||
333 | |||
334 | /** | ||
335 | * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command | ||
336 | * | ||
337 | * @header: command sent to device (compliant to WHCI 0.95) | ||
338 | * @size: size of command sent to device | ||
339 | * | ||
340 | * WUSB has an extra bExplicit field - we assume always explicit | ||
341 | * negotiation so this field is set. The command expected by the device is | ||
342 | * thus larger than the one prepared by the driver so we need to | ||
343 | * reallocate memory to accommodate this. | ||
344 | * We trust the driver to send us the correct data so no checking is done | ||
345 | * on incoming data - evn though it is variable length. | ||
346 | */ | ||
347 | static | ||
348 | int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc, | ||
349 | struct uwb_rccb **header, | ||
350 | size_t *size) | ||
351 | { | ||
352 | struct uwb_rc_cmd_set_drp_ie *orgcmd; | ||
353 | struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd; | ||
354 | size_t ielength; | ||
355 | |||
356 | orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb); | ||
357 | ielength = le16_to_cpu(orgcmd->wIELength); | ||
358 | cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL); | ||
359 | if (cmd == NULL) | ||
360 | return -ENOMEM; | ||
361 | cmd->rccb = orgcmd->rccb; | ||
362 | cmd->bExplicit = 0; | ||
363 | cmd->wIELength = orgcmd->wIELength; | ||
364 | memcpy(cmd->IEData, orgcmd->IEData, ielength); | ||
365 | *header = &cmd->rccb; | ||
366 | *size = sizeof(*cmd) + ielength; | ||
367 | return 1; /* calling function will free memory */ | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * Filter data from WHCI driver to WUSB device | ||
373 | * | ||
374 | * @header: WHCI 0.95 compliant command from driver | ||
375 | * @size: length of command | ||
376 | * | ||
377 | * The routine managing commands to the device (uwb_rc_cmd()) will call the | ||
378 | * filtering function pointer (if it exists) before it passes any data to | ||
379 | * the device. At this time the command has been formatted according to | ||
380 | * WHCI 0.95 and is ready to be sent to the device. | ||
381 | * | ||
382 | * The filter function will be provided with the current command and its | ||
383 | * length. The function will manipulate the command if necessary and | ||
384 | * potentially reallocate memory for a command that needed more memory that | ||
385 | * the given command. If new memory was created the function will return 1 | ||
386 | * to indicate to the calling function that the memory need to be freed | ||
387 | * when not needed any more. The size will contain the new length of the | ||
388 | * command. | ||
389 | * If memory has not been allocated we rely on the original mechanisms to | ||
390 | * free the memory of the command - even when we reduce the value of size. | ||
391 | */ | ||
392 | static | ||
393 | int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header, | ||
394 | size_t *size) | ||
395 | { | ||
396 | int result; | ||
397 | struct uwb_rccb *rccb = *header; | ||
398 | int cmd = le16_to_cpu(rccb->wCommand); | ||
399 | switch (cmd) { | ||
400 | case UWB_RC_CMD_SCAN: | ||
401 | result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size); | ||
402 | break; | ||
403 | case UWB_RC_CMD_SET_DRP_IE: | ||
404 | result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size); | ||
405 | break; | ||
406 | default: | ||
407 | result = -ENOANO; | ||
408 | break; | ||
409 | } | ||
410 | return result; | ||
411 | } | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Filter data from WHCI driver to WUSB device | ||
416 | * | ||
417 | * @header: WHCI 0.95 compliant command from driver | ||
418 | * @size: length of command | ||
419 | * | ||
420 | * Filter commands based on which protocol the device supports. The WUSB | ||
421 | * errata should be the same as WHCI 0.95 so we do not filter that here - | ||
422 | * only WUSB 1.0. | ||
423 | */ | ||
424 | static | ||
425 | int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header, | ||
426 | size_t *size) | ||
427 | { | ||
428 | int result = -ENOANO; | ||
429 | if (rc->version == 0x0100) | ||
430 | result = hwarc_filter_cmd_WUSB_0100(rc, header, size); | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Compute return value as sum of incoming value and value at given offset | ||
437 | * | ||
438 | * @rceb: event for which we compute the size, it contains a variable | ||
439 | * length field. | ||
440 | * @core_size: size of the "non variable" part of the event | ||
441 | * @offset: place in event where the length of the variable part is stored | ||
442 | * @buf_size: total length of buffer in which event arrived - we need to make | ||
443 | * sure we read the offset in memory that is still part of the event | ||
444 | */ | ||
445 | static | ||
446 | ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, | ||
447 | size_t core_size, size_t offset, | ||
448 | const size_t buf_size) | ||
449 | { | ||
450 | ssize_t size = -ENOSPC; | ||
451 | const void *ptr = rceb; | ||
452 | size_t type_size = sizeof(__le16); | ||
453 | struct device *dev = &rc->uwb_dev.dev; | ||
454 | |||
455 | if (offset + type_size >= buf_size) { | ||
456 | dev_err(dev, "Not enough data to read extra size of event " | ||
457 | "0x%02x/%04x/%02x, only got %zu bytes.\n", | ||
458 | rceb->bEventType, le16_to_cpu(rceb->wEvent), | ||
459 | rceb->bEventContext, buf_size); | ||
460 | goto out; | ||
461 | } | ||
462 | ptr += offset; | ||
463 | size = core_size + le16_to_cpu(*(__le16 *)ptr); | ||
464 | out: | ||
465 | return size; | ||
466 | } | ||
467 | |||
468 | |||
469 | /* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */ | ||
470 | struct uwb_rc_evt_bp_slot_change_WUSB_0100 { | ||
471 | struct uwb_rceb rceb; | ||
472 | u8 bSlotNumber; | ||
473 | } __attribute__((packed)); | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Filter data from WUSB device to WHCI driver | ||
478 | * | ||
479 | * @header: incoming event | ||
480 | * @buf_size: size of buffer in which event arrived | ||
481 | * @_event_size: actual size of event in the buffer | ||
482 | * @new_size: size of event after filtered | ||
483 | * | ||
484 | * We don't know how the buffer is constructed - there may be more than one | ||
485 | * event in it so buffer length does not determine event length. We first | ||
486 | * determine the expected size of the incoming event. This value is passed | ||
487 | * back only if the actual filtering succeeded (so we know the computed | ||
488 | * expected size is correct). This value will be zero if | ||
489 | * the event did not need any filtering. | ||
490 | * | ||
491 | * WHCI interprets the BP Slot Change event's data differently than | ||
492 | * WUSB. The event sizes are exactly the same. The data field | ||
493 | * indicates the new beacon slot in which a RC is transmitting its | ||
494 | * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368 | ||
495 | * 17.16 (Table 117)). We thus know that the WUSB value will not set | ||
496 | * the bit bNoSlot, so we don't really do anything (placeholder). | ||
497 | */ | ||
498 | static | ||
499 | int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header, | ||
500 | const size_t buf_size, size_t *_real_size, | ||
501 | size_t *_new_size) | ||
502 | { | ||
503 | int result = -ENOANO; | ||
504 | struct uwb_rceb *rceb = *header; | ||
505 | int event = le16_to_cpu(rceb->wEvent); | ||
506 | size_t event_size; | ||
507 | size_t core_size, offset; | ||
508 | |||
509 | if (rceb->bEventType != UWB_RC_CET_GENERAL) | ||
510 | goto out; | ||
511 | switch (event) { | ||
512 | case UWB_RC_EVT_BEACON: | ||
513 | core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100); | ||
514 | offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100, | ||
515 | wBeaconInfoLength); | ||
516 | event_size = hwarc_get_event_size(rc, rceb, core_size, | ||
517 | offset, buf_size); | ||
518 | if (event_size < 0) | ||
519 | goto out; | ||
520 | *_real_size = event_size; | ||
521 | result = hwarc_filter_evt_beacon_WUSB_0100(rc, header, | ||
522 | buf_size, _new_size); | ||
523 | break; | ||
524 | case UWB_RC_EVT_BP_SLOT_CHANGE: | ||
525 | *_new_size = *_real_size = | ||
526 | sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100); | ||
527 | result = 0; | ||
528 | break; | ||
529 | |||
530 | case UWB_RC_EVT_DRP_AVAIL: | ||
531 | core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100); | ||
532 | offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100, | ||
533 | wIELength); | ||
534 | event_size = hwarc_get_event_size(rc, rceb, core_size, | ||
535 | offset, buf_size); | ||
536 | if (event_size < 0) | ||
537 | goto out; | ||
538 | *_real_size = event_size; | ||
539 | result = hwarc_filter_evt_drp_avail_WUSB_0100( | ||
540 | rc, header, buf_size, _new_size); | ||
541 | break; | ||
542 | |||
543 | case UWB_RC_EVT_DRP: | ||
544 | core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100); | ||
545 | offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength); | ||
546 | event_size = hwarc_get_event_size(rc, rceb, core_size, | ||
547 | offset, buf_size); | ||
548 | if (event_size < 0) | ||
549 | goto out; | ||
550 | *_real_size = event_size; | ||
551 | result = hwarc_filter_evt_drp_WUSB_0100(rc, header, | ||
552 | buf_size, _new_size); | ||
553 | break; | ||
554 | |||
555 | default: | ||
556 | break; | ||
557 | } | ||
558 | out: | ||
559 | return result; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * Filter data from WUSB device to WHCI driver | ||
564 | * | ||
565 | * @header: incoming event | ||
566 | * @buf_size: size of buffer in which event arrived | ||
567 | * @_event_size: actual size of event in the buffer | ||
568 | * @_new_size: size of event after filtered | ||
569 | * | ||
570 | * Filter events based on which protocol the device supports. The WUSB | ||
571 | * errata should be the same as WHCI 0.95 so we do not filter that here - | ||
572 | * only WUSB 1.0. | ||
573 | * | ||
574 | * If we don't handle it, we return -ENOANO (why the weird error code? | ||
575 | * well, so if I get it, I can pinpoint in the code that raised | ||
576 | * it...after all, not too many places use the higher error codes). | ||
577 | */ | ||
578 | static | ||
579 | int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header, | ||
580 | const size_t buf_size, size_t *_real_size, | ||
581 | size_t *_new_size) | ||
582 | { | ||
583 | int result = -ENOANO; | ||
584 | if (rc->version == 0x0100) | ||
585 | result = hwarc_filter_event_WUSB_0100( | ||
586 | rc, header, buf_size, _real_size, _new_size); | ||
587 | return result; | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Execute an UWB RC command on HWA | ||
593 | * | ||
594 | * @rc: Instance of a Radio Controller that is a HWA | ||
595 | * @cmd: Buffer containing the RCCB and payload to execute | ||
596 | * @cmd_size: Size of the command buffer. | ||
597 | * | ||
598 | * NOTE: rc's mutex has to be locked | ||
599 | */ | ||
600 | static | ||
601 | int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size) | ||
602 | { | ||
603 | struct hwarc *hwarc = uwb_rc->priv; | ||
604 | return usb_control_msg( | ||
605 | hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0), | ||
606 | WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
607 | 0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber, | ||
608 | (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */); | ||
609 | } | ||
610 | |||
611 | static | ||
612 | int hwarc_reset(struct uwb_rc *uwb_rc) | ||
613 | { | ||
614 | struct hwarc *hwarc = uwb_rc->priv; | ||
615 | return usb_reset_device(hwarc->usb_dev); | ||
616 | } | ||
617 | |||
618 | /** | ||
619 | * Callback for the notification and event endpoint | ||
620 | * | ||
621 | * Check's that everything is fine and then passes the read data to | ||
622 | * the notification/event handling mechanism (neh). | ||
623 | */ | ||
624 | static | ||
625 | void hwarc_neep_cb(struct urb *urb) | ||
626 | { | ||
627 | struct hwarc *hwarc = urb->context; | ||
628 | struct usb_interface *usb_iface = hwarc->usb_iface; | ||
629 | struct device *dev = &usb_iface->dev; | ||
630 | int result; | ||
631 | |||
632 | switch (result = urb->status) { | ||
633 | case 0: | ||
634 | d_printf(3, dev, "NEEP: receive stat %d, %zu bytes\n", | ||
635 | urb->status, (size_t)urb->actual_length); | ||
636 | uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer, | ||
637 | urb->actual_length); | ||
638 | break; | ||
639 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
640 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
641 | d_printf(2, dev, "NEEP: URB reset/noent %d\n", urb->status); | ||
642 | goto out; | ||
643 | case -ESHUTDOWN: /* going away! */ | ||
644 | d_printf(2, dev, "NEEP: URB down %d\n", urb->status); | ||
645 | goto out; | ||
646 | default: /* On general errors, retry unless it gets ugly */ | ||
647 | if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS, | ||
648 | EDC_ERROR_TIMEFRAME)) | ||
649 | goto error_exceeded; | ||
650 | dev_err(dev, "NEEP: URB error %d\n", urb->status); | ||
651 | } | ||
652 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
653 | d_printf(3, dev, "NEEP: submit %d\n", result); | ||
654 | if (result < 0) { | ||
655 | dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n", | ||
656 | result); | ||
657 | goto error; | ||
658 | } | ||
659 | out: | ||
660 | return; | ||
661 | |||
662 | error_exceeded: | ||
663 | dev_err(dev, "NEEP: URB max acceptable errors " | ||
664 | "exceeded, resetting device\n"); | ||
665 | error: | ||
666 | uwb_rc_neh_error(hwarc->uwb_rc, result); | ||
667 | uwb_rc_reset_all(hwarc->uwb_rc); | ||
668 | return; | ||
669 | } | ||
670 | |||
671 | static void hwarc_init(struct hwarc *hwarc) | ||
672 | { | ||
673 | edc_init(&hwarc->neep_edc); | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * Initialize the notification/event endpoint stuff | ||
678 | * | ||
679 | * Note this is effectively a parallel thread; it knows that | ||
680 | * hwarc->uwb_rc always exists because the existence of a 'hwarc' | ||
681 | * means that there is a reverence on the hwarc->uwb_rc (see | ||
682 | * _probe()), and thus _neep_cb() can execute safely. | ||
683 | */ | ||
684 | static int hwarc_neep_init(struct uwb_rc *rc) | ||
685 | { | ||
686 | struct hwarc *hwarc = rc->priv; | ||
687 | struct usb_interface *iface = hwarc->usb_iface; | ||
688 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
689 | struct device *dev = &iface->dev; | ||
690 | int result; | ||
691 | struct usb_endpoint_descriptor *epd; | ||
692 | |||
693 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
694 | hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL); | ||
695 | if (hwarc->rd_buffer == NULL) { | ||
696 | dev_err(dev, "Unable to allocate notification's read buffer\n"); | ||
697 | goto error_rd_buffer; | ||
698 | } | ||
699 | hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
700 | if (hwarc->neep_urb == NULL) { | ||
701 | dev_err(dev, "Unable to allocate notification URB\n"); | ||
702 | goto error_urb_alloc; | ||
703 | } | ||
704 | usb_fill_int_urb(hwarc->neep_urb, usb_dev, | ||
705 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
706 | hwarc->rd_buffer, PAGE_SIZE, | ||
707 | hwarc_neep_cb, hwarc, epd->bInterval); | ||
708 | result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC); | ||
709 | if (result < 0) { | ||
710 | dev_err(dev, "Cannot submit notification URB: %d\n", result); | ||
711 | goto error_neep_submit; | ||
712 | } | ||
713 | return 0; | ||
714 | |||
715 | error_neep_submit: | ||
716 | usb_free_urb(hwarc->neep_urb); | ||
717 | error_urb_alloc: | ||
718 | free_page((unsigned long)hwarc->rd_buffer); | ||
719 | error_rd_buffer: | ||
720 | return -ENOMEM; | ||
721 | } | ||
722 | |||
723 | |||
724 | /** Clean up all the notification endpoint resources */ | ||
725 | static void hwarc_neep_release(struct uwb_rc *rc) | ||
726 | { | ||
727 | struct hwarc *hwarc = rc->priv; | ||
728 | |||
729 | usb_kill_urb(hwarc->neep_urb); | ||
730 | usb_free_urb(hwarc->neep_urb); | ||
731 | free_page((unsigned long)hwarc->rd_buffer); | ||
732 | } | ||
733 | |||
734 | /** | ||
735 | * Get the version from class-specific descriptor | ||
736 | * | ||
737 | * NOTE: this descriptor comes with the big bundled configuration | ||
738 | * descriptor that includes the interfaces' and endpoints', so | ||
739 | * we just look for it in the cached copy kept by the USB stack. | ||
740 | * | ||
741 | * NOTE2: We convert LE fields to CPU order. | ||
742 | */ | ||
743 | static int hwarc_get_version(struct uwb_rc *rc) | ||
744 | { | ||
745 | int result; | ||
746 | |||
747 | struct hwarc *hwarc = rc->priv; | ||
748 | struct uwb_rc_control_intf_class_desc *descr; | ||
749 | struct device *dev = &rc->uwb_dev.dev; | ||
750 | struct usb_device *usb_dev = hwarc->usb_dev; | ||
751 | char *itr; | ||
752 | struct usb_descriptor_header *hdr; | ||
753 | size_t itr_size, actconfig_idx; | ||
754 | u16 version; | ||
755 | |||
756 | actconfig_idx = (usb_dev->actconfig - usb_dev->config) / | ||
757 | sizeof(usb_dev->config[0]); | ||
758 | itr = usb_dev->rawdescriptors[actconfig_idx]; | ||
759 | itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); | ||
760 | while (itr_size >= sizeof(*hdr)) { | ||
761 | hdr = (struct usb_descriptor_header *) itr; | ||
762 | d_printf(3, dev, "Extra device descriptor: " | ||
763 | "type %02x/%u bytes @ %zu (%zu left)\n", | ||
764 | hdr->bDescriptorType, hdr->bLength, | ||
765 | (itr - usb_dev->rawdescriptors[actconfig_idx]), | ||
766 | itr_size); | ||
767 | if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL) | ||
768 | goto found; | ||
769 | itr += hdr->bLength; | ||
770 | itr_size -= hdr->bLength; | ||
771 | } | ||
772 | dev_err(dev, "cannot find Radio Control Interface Class descriptor\n"); | ||
773 | return -ENODEV; | ||
774 | |||
775 | found: | ||
776 | result = -EINVAL; | ||
777 | if (hdr->bLength > itr_size) { /* is it available? */ | ||
778 | dev_err(dev, "incomplete Radio Control Interface Class " | ||
779 | "descriptor (%zu bytes left, %u needed)\n", | ||
780 | itr_size, hdr->bLength); | ||
781 | goto error; | ||
782 | } | ||
783 | if (hdr->bLength < sizeof(*descr)) { | ||
784 | dev_err(dev, "short Radio Control Interface Class " | ||
785 | "descriptor\n"); | ||
786 | goto error; | ||
787 | } | ||
788 | descr = (struct uwb_rc_control_intf_class_desc *) hdr; | ||
789 | /* Make LE fields CPU order */ | ||
790 | version = __le16_to_cpu(descr->bcdRCIVersion); | ||
791 | if (version != 0x0100) { | ||
792 | dev_err(dev, "Device reports protocol version 0x%04x. We " | ||
793 | "do not support that. \n", version); | ||
794 | result = -EINVAL; | ||
795 | goto error; | ||
796 | } | ||
797 | rc->version = version; | ||
798 | d_printf(3, dev, "Device supports WUSB protocol version 0x%04x \n", | ||
799 | rc->version); | ||
800 | result = 0; | ||
801 | error: | ||
802 | return result; | ||
803 | } | ||
804 | |||
805 | /* | ||
806 | * By creating a 'uwb_rc', we have a reference on it -- that reference | ||
807 | * is the one we drop when we disconnect. | ||
808 | * | ||
809 | * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there | ||
810 | * is only one altsetting allowed. | ||
811 | */ | ||
812 | static int hwarc_probe(struct usb_interface *iface, | ||
813 | const struct usb_device_id *id) | ||
814 | { | ||
815 | int result; | ||
816 | struct uwb_rc *uwb_rc; | ||
817 | struct hwarc *hwarc; | ||
818 | struct device *dev = &iface->dev; | ||
819 | |||
820 | result = -ENOMEM; | ||
821 | uwb_rc = uwb_rc_alloc(); | ||
822 | if (uwb_rc == NULL) { | ||
823 | dev_err(dev, "unable to allocate RC instance\n"); | ||
824 | goto error_rc_alloc; | ||
825 | } | ||
826 | hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL); | ||
827 | if (hwarc == NULL) { | ||
828 | dev_err(dev, "unable to allocate HWA RC instance\n"); | ||
829 | goto error_alloc; | ||
830 | } | ||
831 | hwarc_init(hwarc); | ||
832 | hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface)); | ||
833 | hwarc->usb_iface = usb_get_intf(iface); | ||
834 | hwarc->uwb_rc = uwb_rc; | ||
835 | |||
836 | uwb_rc->owner = THIS_MODULE; | ||
837 | uwb_rc->start = hwarc_neep_init; | ||
838 | uwb_rc->stop = hwarc_neep_release; | ||
839 | uwb_rc->cmd = hwarc_cmd; | ||
840 | uwb_rc->reset = hwarc_reset; | ||
841 | if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) { | ||
842 | uwb_rc->filter_cmd = NULL; | ||
843 | uwb_rc->filter_event = NULL; | ||
844 | } else { | ||
845 | uwb_rc->filter_cmd = hwarc_filter_cmd; | ||
846 | uwb_rc->filter_event = hwarc_filter_event; | ||
847 | } | ||
848 | |||
849 | result = uwb_rc_add(uwb_rc, dev, hwarc); | ||
850 | if (result < 0) | ||
851 | goto error_rc_add; | ||
852 | result = hwarc_get_version(uwb_rc); | ||
853 | if (result < 0) { | ||
854 | dev_err(dev, "cannot retrieve version of RC \n"); | ||
855 | goto error_get_version; | ||
856 | } | ||
857 | usb_set_intfdata(iface, hwarc); | ||
858 | return 0; | ||
859 | |||
860 | error_get_version: | ||
861 | uwb_rc_rm(uwb_rc); | ||
862 | error_rc_add: | ||
863 | usb_put_intf(iface); | ||
864 | usb_put_dev(hwarc->usb_dev); | ||
865 | error_alloc: | ||
866 | uwb_rc_put(uwb_rc); | ||
867 | error_rc_alloc: | ||
868 | return result; | ||
869 | } | ||
870 | |||
871 | static void hwarc_disconnect(struct usb_interface *iface) | ||
872 | { | ||
873 | struct hwarc *hwarc = usb_get_intfdata(iface); | ||
874 | struct uwb_rc *uwb_rc = hwarc->uwb_rc; | ||
875 | |||
876 | usb_set_intfdata(hwarc->usb_iface, NULL); | ||
877 | uwb_rc_rm(uwb_rc); | ||
878 | usb_put_intf(hwarc->usb_iface); | ||
879 | usb_put_dev(hwarc->usb_dev); | ||
880 | d_printf(1, &hwarc->usb_iface->dev, "freed hwarc %p\n", hwarc); | ||
881 | kfree(hwarc); | ||
882 | uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */ | ||
883 | } | ||
884 | |||
885 | /** USB device ID's that we handle */ | ||
886 | static struct usb_device_id hwarc_id_table[] = { | ||
887 | /* D-Link DUB-1210 */ | ||
888 | { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02), | ||
889 | .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, | ||
890 | /* Intel i1480 (using firmware 1.3PA2-20070828) */ | ||
891 | { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02), | ||
892 | .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, | ||
893 | /* Generic match for the Radio Control interface */ | ||
894 | { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), }, | ||
895 | { }, | ||
896 | }; | ||
897 | MODULE_DEVICE_TABLE(usb, hwarc_id_table); | ||
898 | |||
899 | static struct usb_driver hwarc_driver = { | ||
900 | .name = "hwa-rc", | ||
901 | .probe = hwarc_probe, | ||
902 | .disconnect = hwarc_disconnect, | ||
903 | .id_table = hwarc_id_table, | ||
904 | }; | ||
905 | |||
906 | static int __init hwarc_driver_init(void) | ||
907 | { | ||
908 | int result; | ||
909 | result = usb_register(&hwarc_driver); | ||
910 | if (result < 0) | ||
911 | printk(KERN_ERR "HWA-RC: Cannot register USB driver: %d\n", | ||
912 | result); | ||
913 | return result; | ||
914 | |||
915 | } | ||
916 | module_init(hwarc_driver_init); | ||
917 | |||
918 | static void __exit hwarc_driver_exit(void) | ||
919 | { | ||
920 | usb_deregister(&hwarc_driver); | ||
921 | } | ||
922 | module_exit(hwarc_driver_exit); | ||
923 | |||
924 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
925 | MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver"); | ||
926 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile new file mode 100644 index 000000000000..212bbc7d4c32 --- /dev/null +++ b/drivers/uwb/i1480/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o | ||
2 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/ | ||
diff --git a/drivers/uwb/i1480/dfu/Makefile b/drivers/uwb/i1480/dfu/Makefile new file mode 100644 index 000000000000..bd1b9f25424c --- /dev/null +++ b/drivers/uwb/i1480/dfu/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o | ||
2 | |||
3 | i1480-dfu-usb-objs := \ | ||
4 | dfu.o \ | ||
5 | mac.o \ | ||
6 | phy.o \ | ||
7 | usb.o | ||
8 | |||
9 | |||
diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c new file mode 100644 index 000000000000..9097b3b30385 --- /dev/null +++ b/drivers/uwb/i1480/dfu/dfu.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * Main driver | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Common code for firmware upload used by the USB and PCI version; | ||
24 | * i1480_fw_upload() takes a device descriptor and uses the function | ||
25 | * pointers it provides to upload firmware and prepare the PHY. | ||
26 | * | ||
27 | * As well, provides common functions used by the rest of the code. | ||
28 | */ | ||
29 | #include "i1480-dfu.h" | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/uwb.h> | ||
35 | #include <linux/random.h> | ||
36 | |||
37 | #define D_LOCAL 0 | ||
38 | #include <linux/uwb/debug.h> | ||
39 | |||
40 | /** | ||
41 | * i1480_rceb_check - Check RCEB for expected field values | ||
42 | * @i1480: pointer to device for which RCEB is being checked | ||
43 | * @rceb: RCEB being checked | ||
44 | * @cmd: which command the RCEB is related to | ||
45 | * @context: expected context | ||
46 | * @expected_type: expected event type | ||
47 | * @expected_event: expected event | ||
48 | * | ||
49 | * If @cmd is NULL, do not print error messages, but still return an error | ||
50 | * code. | ||
51 | * | ||
52 | * Return 0 if @rceb matches the expected values, -EINVAL otherwise. | ||
53 | */ | ||
54 | int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb, | ||
55 | const char *cmd, u8 context, u8 expected_type, | ||
56 | unsigned expected_event) | ||
57 | { | ||
58 | int result = 0; | ||
59 | struct device *dev = i1480->dev; | ||
60 | if (rceb->bEventContext != context) { | ||
61 | if (cmd) | ||
62 | dev_err(dev, "%s: unexpected context id 0x%02x " | ||
63 | "(expected 0x%02x)\n", cmd, | ||
64 | rceb->bEventContext, context); | ||
65 | result = -EINVAL; | ||
66 | } | ||
67 | if (rceb->bEventType != expected_type) { | ||
68 | if (cmd) | ||
69 | dev_err(dev, "%s: unexpected event type 0x%02x " | ||
70 | "(expected 0x%02x)\n", cmd, | ||
71 | rceb->bEventType, expected_type); | ||
72 | result = -EINVAL; | ||
73 | } | ||
74 | if (le16_to_cpu(rceb->wEvent) != expected_event) { | ||
75 | if (cmd) | ||
76 | dev_err(dev, "%s: unexpected event 0x%04x " | ||
77 | "(expected 0x%04x)\n", cmd, | ||
78 | le16_to_cpu(rceb->wEvent), expected_event); | ||
79 | result = -EINVAL; | ||
80 | } | ||
81 | return result; | ||
82 | } | ||
83 | EXPORT_SYMBOL_GPL(i1480_rceb_check); | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Execute a Radio Control Command | ||
88 | * | ||
89 | * Command data has to be in i1480->cmd_buf. | ||
90 | * | ||
91 | * @returns size of the reply data filled in i1480->evt_buf or < 0 errno | ||
92 | * code on error. | ||
93 | */ | ||
94 | ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, | ||
95 | size_t reply_size) | ||
96 | { | ||
97 | ssize_t result; | ||
98 | struct uwb_rceb *reply = i1480->evt_buf; | ||
99 | struct uwb_rccb *cmd = i1480->cmd_buf; | ||
100 | u16 expected_event = reply->wEvent; | ||
101 | u8 expected_type = reply->bEventType; | ||
102 | u8 context; | ||
103 | |||
104 | d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); | ||
105 | init_completion(&i1480->evt_complete); | ||
106 | i1480->evt_result = -EINPROGRESS; | ||
107 | do { | ||
108 | get_random_bytes(&context, 1); | ||
109 | } while (context == 0x00 || context == 0xff); | ||
110 | cmd->bCommandContext = context; | ||
111 | result = i1480->cmd(i1480, cmd_name, cmd_size); | ||
112 | if (result < 0) | ||
113 | goto error; | ||
114 | /* wait for the callback to report a event was received */ | ||
115 | result = wait_for_completion_interruptible_timeout( | ||
116 | &i1480->evt_complete, HZ); | ||
117 | if (result == 0) { | ||
118 | result = -ETIMEDOUT; | ||
119 | goto error; | ||
120 | } | ||
121 | if (result < 0) | ||
122 | goto error; | ||
123 | result = i1480->evt_result; | ||
124 | if (result < 0) { | ||
125 | dev_err(i1480->dev, "%s: command reply reception failed: %zd\n", | ||
126 | cmd_name, result); | ||
127 | goto error; | ||
128 | } | ||
129 | /* | ||
130 | * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a | ||
131 | * spurious notification after firmware is downloaded. So check whether | ||
132 | * the receibed RCEB is such notification before assuming that the | ||
133 | * command has failed. | ||
134 | */ | ||
135 | if (i1480_rceb_check(i1480, i1480->evt_buf, NULL, | ||
136 | 0, 0xfd, 0x0022) == 0) { | ||
137 | /* Now wait for the actual RCEB for this command. */ | ||
138 | result = i1480->wait_init_done(i1480); | ||
139 | if (result < 0) | ||
140 | goto error; | ||
141 | result = i1480->evt_result; | ||
142 | } | ||
143 | if (result != reply_size) { | ||
144 | dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n", | ||
145 | cmd_name, result, reply_size); | ||
146 | result = -EINVAL; | ||
147 | goto error; | ||
148 | } | ||
149 | /* Verify we got the right event in response */ | ||
150 | result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context, | ||
151 | expected_type, expected_event); | ||
152 | error: | ||
153 | d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n", | ||
154 | i1480, cmd_name, cmd_size, result); | ||
155 | return result; | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(i1480_cmd); | ||
158 | |||
159 | |||
160 | static | ||
161 | int i1480_print_state(struct i1480 *i1480) | ||
162 | { | ||
163 | int result; | ||
164 | u32 *buf = (u32 *) i1480->cmd_buf; | ||
165 | |||
166 | result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf)); | ||
167 | if (result < 0) { | ||
168 | dev_err(i1480->dev, "cannot read U & L states: %d\n", result); | ||
169 | goto error; | ||
170 | } | ||
171 | dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]); | ||
172 | error: | ||
173 | return result; | ||
174 | } | ||
175 | |||
176 | |||
177 | /* | ||
178 | * PCI probe, firmware uploader | ||
179 | * | ||
180 | * _mac_fw_upload() will call rc_setup(), which needs an rc_release(). | ||
181 | */ | ||
182 | int i1480_fw_upload(struct i1480 *i1480) | ||
183 | { | ||
184 | int result; | ||
185 | |||
186 | result = i1480_pre_fw_upload(i1480); /* PHY pre fw */ | ||
187 | if (result < 0 && result != -ENOENT) { | ||
188 | i1480_print_state(i1480); | ||
189 | goto error; | ||
190 | } | ||
191 | result = i1480_mac_fw_upload(i1480); /* MAC fw */ | ||
192 | if (result < 0) { | ||
193 | if (result == -ENOENT) | ||
194 | dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n", | ||
195 | i1480->mac_fw_name); | ||
196 | else | ||
197 | i1480_print_state(i1480); | ||
198 | goto error; | ||
199 | } | ||
200 | result = i1480_phy_fw_upload(i1480); /* PHY fw */ | ||
201 | if (result < 0 && result != -ENOENT) { | ||
202 | i1480_print_state(i1480); | ||
203 | goto error_rc_release; | ||
204 | } | ||
205 | /* | ||
206 | * FIXME: find some reliable way to check whether firmware is running | ||
207 | * properly. Maybe use some standard request that has no side effects? | ||
208 | */ | ||
209 | dev_info(i1480->dev, "firmware uploaded successfully\n"); | ||
210 | error_rc_release: | ||
211 | if (i1480->rc_release) | ||
212 | i1480->rc_release(i1480); | ||
213 | result = 0; | ||
214 | error: | ||
215 | return result; | ||
216 | } | ||
217 | EXPORT_SYMBOL_GPL(i1480_fw_upload); | ||
diff --git a/drivers/uwb/i1480/dfu/i1480-dfu.h b/drivers/uwb/i1480/dfu/i1480-dfu.h new file mode 100644 index 000000000000..46f45e800f36 --- /dev/null +++ b/drivers/uwb/i1480/dfu/i1480-dfu.h | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * i1480 Device Firmware Upload | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * This driver is the firmware uploader for the Intel Wireless UWB | ||
23 | * Link 1480 device (both in the USB and PCI incarnations). | ||
24 | * | ||
25 | * The process is quite simple: we stop the device, write the firmware | ||
26 | * to its memory and then restart it. Wait for the device to let us | ||
27 | * know it is done booting firmware. Ready. | ||
28 | * | ||
29 | * We might have to upload before or after a phy firmware (which might | ||
30 | * be done in two methods, using a normal firmware image or through | ||
31 | * the MPI port). | ||
32 | * | ||
33 | * Because USB and PCI use common methods, we just make ops out of the | ||
34 | * common operations (read, write, wait_init_done and cmd) and | ||
35 | * implement them in usb.c and pci.c. | ||
36 | * | ||
37 | * The flow is (some parts omitted): | ||
38 | * | ||
39 | * i1480_{usb,pci}_probe() On enumerate/discovery | ||
40 | * i1480_fw_upload() | ||
41 | * i1480_pre_fw_upload() | ||
42 | * __mac_fw_upload() | ||
43 | * fw_hdrs_load() | ||
44 | * mac_fw_hdrs_push() | ||
45 | * i1480->write() [i1480_{usb,pci}_write()] | ||
46 | * i1480_fw_cmp() | ||
47 | * i1480->read() [i1480_{usb,pci}_read()] | ||
48 | * i1480_mac_fw_upload() | ||
49 | * __mac_fw_upload() | ||
50 | * i1480->setup(() | ||
51 | * i1480->wait_init_done() | ||
52 | * i1480_cmd_reset() | ||
53 | * i1480->cmd() [i1480_{usb,pci}_cmd()] | ||
54 | * ... | ||
55 | * i1480_phy_fw_upload() | ||
56 | * request_firmware() | ||
57 | * i1480_mpi_write() | ||
58 | * i1480->cmd() [i1480_{usb,pci}_cmd()] | ||
59 | * | ||
60 | * Once the probe function enumerates the device and uploads the | ||
61 | * firmware, we just exit with -ENODEV, as we don't really want to | ||
62 | * attach to the device. | ||
63 | */ | ||
64 | #ifndef __i1480_DFU_H__ | ||
65 | #define __i1480_DFU_H__ | ||
66 | |||
67 | #include <linux/uwb/spec.h> | ||
68 | #include <linux/types.h> | ||
69 | #include <linux/completion.h> | ||
70 | |||
71 | #define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018)) | ||
72 | |||
73 | #if i1480_FW > 0x00000302 | ||
74 | #define i1480_RCEB_EXTENDED | ||
75 | #endif | ||
76 | |||
77 | struct uwb_rccb; | ||
78 | struct uwb_rceb; | ||
79 | |||
80 | /* | ||
81 | * Common firmware upload handlers | ||
82 | * | ||
83 | * Normally you embed this struct in another one specific to your hw. | ||
84 | * | ||
85 | * @write Write to device's memory from buffer. | ||
86 | * @read Read from device's memory to i1480->evt_buf. | ||
87 | * @setup Setup device after basic firmware is uploaded | ||
88 | * @wait_init_done | ||
89 | * Wait for the device to send a notification saying init | ||
90 | * is done. | ||
91 | * @cmd FOP for issuing the command to the hardware. The | ||
92 | * command data is contained in i1480->cmd_buf and the size | ||
93 | * is supplied as an argument. The command replied is put | ||
94 | * in i1480->evt_buf and the size in i1480->evt_result (or if | ||
95 | * an error, a < 0 errno code). | ||
96 | * | ||
97 | * @cmd_buf Memory buffer used to send commands to the device. | ||
98 | * Allocated by the upper layers i1480_fw_upload(). | ||
99 | * Size has to be @buf_size. | ||
100 | * @evt_buf Memory buffer used to place the async notifications | ||
101 | * received by the hw. Allocated by the upper layers | ||
102 | * i1480_fw_upload(). | ||
103 | * Size has to be @buf_size. | ||
104 | * @cmd_complete | ||
105 | * Low level driver uses this to notify code waiting afor | ||
106 | * an event that the event has arrived and data is in | ||
107 | * i1480->evt_buf (and size/result in i1480->evt_result). | ||
108 | * @hw_rev | ||
109 | * Use this value to activate dfu code to support new revisions | ||
110 | * of hardware. i1480_init() sets this to a default value. | ||
111 | * It should be updated by the USB and PCI code. | ||
112 | */ | ||
113 | struct i1480 { | ||
114 | struct device *dev; | ||
115 | |||
116 | int (*write)(struct i1480 *, u32 addr, const void *, size_t); | ||
117 | int (*read)(struct i1480 *, u32 addr, size_t); | ||
118 | int (*rc_setup)(struct i1480 *); | ||
119 | void (*rc_release)(struct i1480 *); | ||
120 | int (*wait_init_done)(struct i1480 *); | ||
121 | int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size); | ||
122 | const char *pre_fw_name; | ||
123 | const char *mac_fw_name; | ||
124 | const char *mac_fw_name_deprecate; /* FIXME: Will go away */ | ||
125 | const char *phy_fw_name; | ||
126 | u8 hw_rev; | ||
127 | |||
128 | size_t buf_size; /* size of both evt_buf and cmd_buf */ | ||
129 | void *evt_buf, *cmd_buf; | ||
130 | ssize_t evt_result; | ||
131 | struct completion evt_complete; | ||
132 | }; | ||
133 | |||
134 | static inline | ||
135 | void i1480_init(struct i1480 *i1480) | ||
136 | { | ||
137 | i1480->hw_rev = 1; | ||
138 | init_completion(&i1480->evt_complete); | ||
139 | } | ||
140 | |||
141 | extern int i1480_fw_upload(struct i1480 *); | ||
142 | extern int i1480_pre_fw_upload(struct i1480 *); | ||
143 | extern int i1480_mac_fw_upload(struct i1480 *); | ||
144 | extern int i1480_phy_fw_upload(struct i1480 *); | ||
145 | extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t); | ||
146 | extern int i1480_rceb_check(const struct i1480 *, | ||
147 | const struct uwb_rceb *, const char *, u8, | ||
148 | u8, unsigned); | ||
149 | |||
150 | enum { | ||
151 | /* Vendor specific command type */ | ||
152 | i1480_CET_VS1 = 0xfd, | ||
153 | /* i1480 commands */ | ||
154 | i1480_CMD_SET_IP_MAS = 0x000e, | ||
155 | i1480_CMD_GET_MAC_PHY_INFO = 0x0003, | ||
156 | i1480_CMD_MPI_WRITE = 0x000f, | ||
157 | i1480_CMD_MPI_READ = 0x0010, | ||
158 | /* i1480 events */ | ||
159 | #if i1480_FW > 0x00000302 | ||
160 | i1480_EVT_CONFIRM = 0x0002, | ||
161 | i1480_EVT_RM_INIT_DONE = 0x0101, | ||
162 | i1480_EVT_DEV_ADD = 0x0103, | ||
163 | i1480_EVT_DEV_RM = 0x0104, | ||
164 | i1480_EVT_DEV_ID_CHANGE = 0x0105, | ||
165 | i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO, | ||
166 | #else | ||
167 | i1480_EVT_CONFIRM = 0x0002, | ||
168 | i1480_EVT_RM_INIT_DONE = 0x0101, | ||
169 | i1480_EVT_DEV_ADD = 0x0103, | ||
170 | i1480_EVT_DEV_RM = 0x0104, | ||
171 | i1480_EVT_DEV_ID_CHANGE = 0x0105, | ||
172 | i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM, | ||
173 | #endif | ||
174 | }; | ||
175 | |||
176 | |||
177 | struct i1480_evt_confirm { | ||
178 | struct uwb_rceb rceb; | ||
179 | #ifdef i1480_RCEB_EXTENDED | ||
180 | __le16 wParamLength; | ||
181 | #endif | ||
182 | u8 bResultCode; | ||
183 | } __attribute__((packed)); | ||
184 | |||
185 | |||
186 | struct i1480_rceb { | ||
187 | struct uwb_rceb rceb; | ||
188 | #ifdef i1480_RCEB_EXTENDED | ||
189 | __le16 wParamLength; | ||
190 | #endif | ||
191 | } __attribute__((packed)); | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Get MAC & PHY Information confirm event structure | ||
196 | * | ||
197 | * Confirm event returned by the command. | ||
198 | */ | ||
199 | struct i1480_evt_confirm_GMPI { | ||
200 | #if i1480_FW > 0x00000302 | ||
201 | struct uwb_rceb rceb; | ||
202 | __le16 wParamLength; | ||
203 | __le16 status; | ||
204 | u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */ | ||
205 | u8 dev_addr[2]; | ||
206 | __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ | ||
207 | u8 hw_rev; | ||
208 | u8 phy_vendor; | ||
209 | u8 phy_rev; /* major v = >> 8; minor = v & 0xff */ | ||
210 | __le16 mac_caps; | ||
211 | u8 phy_caps[3]; | ||
212 | u8 key_stores; | ||
213 | __le16 mcast_addr_stores; | ||
214 | u8 sec_mode_supported; | ||
215 | #else | ||
216 | struct uwb_rceb rceb; | ||
217 | u8 status; | ||
218 | u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */ | ||
219 | u8 dev_addr[2]; | ||
220 | __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ | ||
221 | __le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */ | ||
222 | __le16 mac_caps; | ||
223 | u8 phy_caps; | ||
224 | u8 key_stores; | ||
225 | __le16 mcast_addr_stores; | ||
226 | u8 sec_mode_supported; | ||
227 | #endif | ||
228 | } __attribute__((packed)); | ||
229 | |||
230 | |||
231 | struct i1480_cmd_mpi_write { | ||
232 | struct uwb_rccb rccb; | ||
233 | __le16 size; | ||
234 | u8 data[]; | ||
235 | }; | ||
236 | |||
237 | |||
238 | struct i1480_cmd_mpi_read { | ||
239 | struct uwb_rccb rccb; | ||
240 | __le16 size; | ||
241 | struct { | ||
242 | u8 page, offset; | ||
243 | } __attribute__((packed)) data[]; | ||
244 | } __attribute__((packed)); | ||
245 | |||
246 | |||
247 | struct i1480_evt_mpi_read { | ||
248 | struct uwb_rceb rceb; | ||
249 | #ifdef i1480_RCEB_EXTENDED | ||
250 | __le16 wParamLength; | ||
251 | #endif | ||
252 | u8 bResultCode; | ||
253 | __le16 size; | ||
254 | struct { | ||
255 | u8 page, offset, value; | ||
256 | } __attribute__((packed)) data[]; | ||
257 | } __attribute__((packed)); | ||
258 | |||
259 | |||
260 | #endif /* #ifndef __i1480_DFU_H__ */ | ||
diff --git a/drivers/uwb/i1480/dfu/mac.c b/drivers/uwb/i1480/dfu/mac.c new file mode 100644 index 000000000000..2e4d8f07c165 --- /dev/null +++ b/drivers/uwb/i1480/dfu/mac.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * MAC Firmware upload implementation | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Implementation of the code for parsing the firmware file (extract | ||
24 | * the headers and binary code chunks) in the fw_*() functions. The | ||
25 | * code to upload pre and mac firmwares is the same, so it uses a | ||
26 | * common entry point in __mac_fw_upload(), which uses the i1480 | ||
27 | * function pointers to push the firmware to the device. | ||
28 | */ | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/firmware.h> | ||
31 | #include <linux/uwb.h> | ||
32 | #include "i1480-dfu.h" | ||
33 | |||
34 | #define D_LOCAL 0 | ||
35 | #include <linux/uwb/debug.h> | ||
36 | |||
37 | /* | ||
38 | * Descriptor for a continuous segment of MAC fw data | ||
39 | */ | ||
40 | struct fw_hdr { | ||
41 | unsigned long address; | ||
42 | size_t length; | ||
43 | const u32 *bin; | ||
44 | struct fw_hdr *next; | ||
45 | }; | ||
46 | |||
47 | |||
48 | /* Free a chain of firmware headers */ | ||
49 | static | ||
50 | void fw_hdrs_free(struct fw_hdr *hdr) | ||
51 | { | ||
52 | struct fw_hdr *next; | ||
53 | |||
54 | while (hdr) { | ||
55 | next = hdr->next; | ||
56 | kfree(hdr); | ||
57 | hdr = next; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | /* Fill a firmware header descriptor from a memory buffer */ | ||
63 | static | ||
64 | int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt, | ||
65 | const char *_data, const u32 *data_itr, const u32 *data_top) | ||
66 | { | ||
67 | size_t hdr_offset = (const char *) data_itr - _data; | ||
68 | size_t remaining_size = (void *) data_top - (void *) data_itr; | ||
69 | if (data_itr + 2 > data_top) { | ||
70 | dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at " | ||
71 | "offset %zu, limit %zu\n", | ||
72 | hdr_cnt, hdr_offset, | ||
73 | (const char *) data_itr + 2 - _data, | ||
74 | (const char *) data_top - _data); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | hdr->next = NULL; | ||
78 | hdr->address = le32_to_cpu(*data_itr++); | ||
79 | hdr->length = le32_to_cpu(*data_itr++); | ||
80 | hdr->bin = data_itr; | ||
81 | if (hdr->length > remaining_size) { | ||
82 | dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; " | ||
83 | "chunk too long (%zu bytes), only %zu left\n", | ||
84 | hdr_cnt, hdr_offset, hdr->length, remaining_size); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Get a buffer where the firmware is supposed to be and create a | ||
93 | * chain of headers linking them together. | ||
94 | * | ||
95 | * @phdr: where to place the pointer to the first header (headers link | ||
96 | * to the next via the @hdr->next ptr); need to free the whole | ||
97 | * chain when done. | ||
98 | * | ||
99 | * @_data: Pointer to the data buffer. | ||
100 | * | ||
101 | * @_data_size: Size of the data buffer (bytes); data size has to be a | ||
102 | * multiple of 4. Function will fail if not. | ||
103 | * | ||
104 | * Goes over the whole binary blob; reads the first chunk and creates | ||
105 | * a fw hdr from it (which points to where the data is in @_data and | ||
106 | * the length of the chunk); then goes on to the next chunk until | ||
107 | * done. Each header is linked to the next. | ||
108 | */ | ||
109 | static | ||
110 | int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr, | ||
111 | const char *_data, size_t data_size) | ||
112 | { | ||
113 | int result; | ||
114 | unsigned hdr_cnt = 0; | ||
115 | u32 *data = (u32 *) _data, *data_itr, *data_top; | ||
116 | struct fw_hdr *hdr, **prev_hdr = phdr; | ||
117 | |||
118 | result = -EINVAL; | ||
119 | /* Check size is ok and pointer is aligned */ | ||
120 | if (data_size % sizeof(u32) != 0) | ||
121 | goto error; | ||
122 | if ((unsigned long) _data % sizeof(u16) != 0) | ||
123 | goto error; | ||
124 | *phdr = NULL; | ||
125 | data_itr = data; | ||
126 | data_top = (u32 *) (_data + data_size); | ||
127 | while (data_itr < data_top) { | ||
128 | result = -ENOMEM; | ||
129 | hdr = kmalloc(sizeof(*hdr), GFP_KERNEL); | ||
130 | if (hdr == NULL) { | ||
131 | dev_err(i1480->dev, "Cannot allocate fw header " | ||
132 | "for chunk #%u\n", hdr_cnt); | ||
133 | goto error_alloc; | ||
134 | } | ||
135 | result = fw_hdr_load(i1480, hdr, hdr_cnt, | ||
136 | _data, data_itr, data_top); | ||
137 | if (result < 0) | ||
138 | goto error_load; | ||
139 | data_itr += 2 + hdr->length; | ||
140 | *prev_hdr = hdr; | ||
141 | prev_hdr = &hdr->next; | ||
142 | hdr_cnt++; | ||
143 | }; | ||
144 | *prev_hdr = NULL; | ||
145 | return 0; | ||
146 | |||
147 | error_load: | ||
148 | kfree(hdr); | ||
149 | error_alloc: | ||
150 | fw_hdrs_free(*phdr); | ||
151 | error: | ||
152 | return result; | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Compares a chunk of fw with one in the devices's memory | ||
158 | * | ||
159 | * @i1480: Device instance | ||
160 | * @hdr: Pointer to the firmware chunk | ||
161 | * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset | ||
162 | * where the difference was found (plus one). | ||
163 | * | ||
164 | * Kind of dirty and simplistic, but does the trick in both the PCI | ||
165 | * and USB version. We do a quick[er] memcmp(), and if it fails, we do | ||
166 | * a byte-by-byte to find the offset. | ||
167 | */ | ||
168 | static | ||
169 | ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr) | ||
170 | { | ||
171 | ssize_t result = 0; | ||
172 | u32 src_itr = 0, cnt; | ||
173 | size_t size = hdr->length*sizeof(hdr->bin[0]); | ||
174 | size_t chunk_size; | ||
175 | u8 *bin = (u8 *) hdr->bin; | ||
176 | |||
177 | while (size > 0) { | ||
178 | chunk_size = size < i1480->buf_size ? size : i1480->buf_size; | ||
179 | result = i1480->read(i1480, hdr->address + src_itr, chunk_size); | ||
180 | if (result < 0) { | ||
181 | dev_err(i1480->dev, "error reading for verification: " | ||
182 | "%zd\n", result); | ||
183 | goto error; | ||
184 | } | ||
185 | if (memcmp(i1480->cmd_buf, bin + src_itr, result)) { | ||
186 | u8 *buf = i1480->cmd_buf; | ||
187 | d_printf(2, i1480->dev, | ||
188 | "original data @ %p + %u, %zu bytes\n", | ||
189 | bin, src_itr, result); | ||
190 | d_dump(4, i1480->dev, bin + src_itr, result); | ||
191 | for (cnt = 0; cnt < result; cnt++) | ||
192 | if (bin[src_itr + cnt] != buf[cnt]) { | ||
193 | dev_err(i1480->dev, "byte failed at " | ||
194 | "src_itr %u cnt %u [0x%02x " | ||
195 | "vs 0x%02x]\n", src_itr, cnt, | ||
196 | bin[src_itr + cnt], buf[cnt]); | ||
197 | result = src_itr + cnt + 1; | ||
198 | goto cmp_failed; | ||
199 | } | ||
200 | } | ||
201 | src_itr += result; | ||
202 | size -= result; | ||
203 | } | ||
204 | result = 0; | ||
205 | error: | ||
206 | cmp_failed: | ||
207 | return result; | ||
208 | } | ||
209 | |||
210 | |||
211 | /** | ||
212 | * Writes firmware headers to the device. | ||
213 | * | ||
214 | * @prd: PRD instance | ||
215 | * @hdr: Processed firmware | ||
216 | * @returns: 0 if ok, < 0 errno on error. | ||
217 | */ | ||
218 | static | ||
219 | int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr, | ||
220 | const char *fw_name, const char *fw_tag) | ||
221 | { | ||
222 | struct device *dev = i1480->dev; | ||
223 | ssize_t result = 0; | ||
224 | struct fw_hdr *hdr_itr; | ||
225 | int verif_retry_count; | ||
226 | |||
227 | d_fnstart(3, dev, "(%p, %p)\n", i1480, hdr); | ||
228 | /* Now, header by header, push them to the hw */ | ||
229 | for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) { | ||
230 | verif_retry_count = 0; | ||
231 | retry: | ||
232 | dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n", | ||
233 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
234 | hdr_itr->address); | ||
235 | result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin, | ||
236 | hdr_itr->length*sizeof(hdr_itr->bin[0])); | ||
237 | if (result < 0) { | ||
238 | dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):" | ||
239 | " %zd\n", fw_tag, fw_name, | ||
240 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
241 | hdr_itr->address, result); | ||
242 | break; | ||
243 | } | ||
244 | result = i1480_fw_cmp(i1480, hdr_itr); | ||
245 | if (result < 0) { | ||
246 | dev_err(dev, "%s fw '%s': verification read " | ||
247 | "failed (%zuB @ 0x%lx): %zd\n", | ||
248 | fw_tag, fw_name, | ||
249 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
250 | hdr_itr->address, result); | ||
251 | break; | ||
252 | } | ||
253 | if (result > 0) { /* Offset where it failed + 1 */ | ||
254 | result--; | ||
255 | dev_err(dev, "%s fw '%s': WARNING: verification " | ||
256 | "failed at 0x%lx: retrying\n", | ||
257 | fw_tag, fw_name, hdr_itr->address + result); | ||
258 | if (++verif_retry_count < 3) | ||
259 | goto retry; /* write this block again! */ | ||
260 | dev_err(dev, "%s fw '%s': verification failed at 0x%lx: " | ||
261 | "tried %d times\n", fw_tag, fw_name, | ||
262 | hdr_itr->address + result, verif_retry_count); | ||
263 | result = -EINVAL; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | d_fnend(3, dev, "(%zd)\n", result); | ||
268 | return result; | ||
269 | } | ||
270 | |||
271 | |||
272 | /** Puts the device in firmware upload mode.*/ | ||
273 | static | ||
274 | int mac_fw_upload_enable(struct i1480 *i1480) | ||
275 | { | ||
276 | int result; | ||
277 | u32 reg = 0x800000c0; | ||
278 | u32 *buffer = (u32 *)i1480->cmd_buf; | ||
279 | |||
280 | if (i1480->hw_rev > 1) | ||
281 | reg = 0x8000d0d4; | ||
282 | result = i1480->read(i1480, reg, sizeof(u32)); | ||
283 | if (result < 0) | ||
284 | goto error_cmd; | ||
285 | *buffer &= ~i1480_FW_UPLOAD_MODE_MASK; | ||
286 | result = i1480->write(i1480, reg, buffer, sizeof(u32)); | ||
287 | if (result < 0) | ||
288 | goto error_cmd; | ||
289 | return 0; | ||
290 | error_cmd: | ||
291 | dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result); | ||
292 | return result; | ||
293 | } | ||
294 | |||
295 | |||
296 | /** Gets the device out of firmware upload mode. */ | ||
297 | static | ||
298 | int mac_fw_upload_disable(struct i1480 *i1480) | ||
299 | { | ||
300 | int result; | ||
301 | u32 reg = 0x800000c0; | ||
302 | u32 *buffer = (u32 *)i1480->cmd_buf; | ||
303 | |||
304 | if (i1480->hw_rev > 1) | ||
305 | reg = 0x8000d0d4; | ||
306 | result = i1480->read(i1480, reg, sizeof(u32)); | ||
307 | if (result < 0) | ||
308 | goto error_cmd; | ||
309 | *buffer |= i1480_FW_UPLOAD_MODE_MASK; | ||
310 | result = i1480->write(i1480, reg, buffer, sizeof(u32)); | ||
311 | if (result < 0) | ||
312 | goto error_cmd; | ||
313 | return 0; | ||
314 | error_cmd: | ||
315 | dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result); | ||
316 | return result; | ||
317 | } | ||
318 | |||
319 | |||
320 | |||
321 | /** | ||
322 | * Generic function for uploading a MAC firmware. | ||
323 | * | ||
324 | * @i1480: Device instance | ||
325 | * @fw_name: Name of firmware file to upload. | ||
326 | * @fw_tag: Name of the firmware type (for messages) | ||
327 | * [eg: MAC, PRE] | ||
328 | * @do_wait: Wait for device to emit initialization done message (0 | ||
329 | * for PRE fws, 1 for MAC fws). | ||
330 | * @returns: 0 if ok, < 0 errno on error. | ||
331 | */ | ||
332 | static | ||
333 | int __mac_fw_upload(struct i1480 *i1480, const char *fw_name, | ||
334 | const char *fw_tag) | ||
335 | { | ||
336 | int result; | ||
337 | const struct firmware *fw; | ||
338 | struct fw_hdr *fw_hdrs; | ||
339 | |||
340 | d_fnstart(3, i1480->dev, "(%p, %s, %s)\n", i1480, fw_name, fw_tag); | ||
341 | result = request_firmware(&fw, fw_name, i1480->dev); | ||
342 | if (result < 0) /* Up to caller to complain on -ENOENT */ | ||
343 | goto out; | ||
344 | d_printf(3, i1480->dev, "%s fw '%s': uploading\n", fw_tag, fw_name); | ||
345 | result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size); | ||
346 | if (result < 0) { | ||
347 | dev_err(i1480->dev, "%s fw '%s': failed to parse firmware " | ||
348 | "file: %d\n", fw_tag, fw_name, result); | ||
349 | goto out_release; | ||
350 | } | ||
351 | result = mac_fw_upload_enable(i1480); | ||
352 | if (result < 0) | ||
353 | goto out_hdrs_release; | ||
354 | result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag); | ||
355 | mac_fw_upload_disable(i1480); | ||
356 | out_hdrs_release: | ||
357 | if (result >= 0) | ||
358 | dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name); | ||
359 | else | ||
360 | dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), " | ||
361 | "power cycle device\n", fw_tag, fw_name, result); | ||
362 | fw_hdrs_free(fw_hdrs); | ||
363 | out_release: | ||
364 | release_firmware(fw); | ||
365 | out: | ||
366 | d_fnend(3, i1480->dev, "(%p, %s, %s) = %d\n", i1480, fw_name, fw_tag, | ||
367 | result); | ||
368 | return result; | ||
369 | } | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Upload a pre-PHY firmware | ||
374 | * | ||
375 | */ | ||
376 | int i1480_pre_fw_upload(struct i1480 *i1480) | ||
377 | { | ||
378 | int result; | ||
379 | result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE"); | ||
380 | if (result == 0) | ||
381 | msleep(400); | ||
382 | return result; | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Reset a the MAC and PHY | ||
388 | * | ||
389 | * @i1480: Device's instance | ||
390 | * @returns: 0 if ok, < 0 errno code on error | ||
391 | * | ||
392 | * We put the command on kmalloc'ed memory as some arches cannot do | ||
393 | * USB from the stack. The reply event is copied from an stage buffer, | ||
394 | * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. | ||
395 | * | ||
396 | * We issue the reset to make sure the UWB controller reinits the PHY; | ||
397 | * this way we can now if the PHY init went ok. | ||
398 | */ | ||
399 | static | ||
400 | int i1480_cmd_reset(struct i1480 *i1480) | ||
401 | { | ||
402 | int result; | ||
403 | struct uwb_rccb *cmd = (void *) i1480->cmd_buf; | ||
404 | struct i1480_evt_reset { | ||
405 | struct uwb_rceb rceb; | ||
406 | u8 bResultCode; | ||
407 | } __attribute__((packed)) *reply = (void *) i1480->evt_buf; | ||
408 | |||
409 | result = -ENOMEM; | ||
410 | cmd->bCommandType = UWB_RC_CET_GENERAL; | ||
411 | cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET); | ||
412 | reply->rceb.bEventType = UWB_RC_CET_GENERAL; | ||
413 | reply->rceb.wEvent = UWB_RC_CMD_RESET; | ||
414 | result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply)); | ||
415 | if (result < 0) | ||
416 | goto out; | ||
417 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
418 | dev_err(i1480->dev, "RESET: command execution failed: %u\n", | ||
419 | reply->bResultCode); | ||
420 | result = -EIO; | ||
421 | } | ||
422 | out: | ||
423 | return result; | ||
424 | |||
425 | } | ||
426 | |||
427 | |||
428 | /* Wait for the MAC FW to start running */ | ||
429 | static | ||
430 | int i1480_fw_is_running_q(struct i1480 *i1480) | ||
431 | { | ||
432 | int cnt = 0; | ||
433 | int result; | ||
434 | u32 *val = (u32 *) i1480->cmd_buf; | ||
435 | |||
436 | d_fnstart(3, i1480->dev, "(i1480 %p)\n", i1480); | ||
437 | for (cnt = 0; cnt < 10; cnt++) { | ||
438 | msleep(100); | ||
439 | result = i1480->read(i1480, 0x80080000, 4); | ||
440 | if (result < 0) { | ||
441 | dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result); | ||
442 | goto out; | ||
443 | } | ||
444 | if (*val == 0x55555555UL) /* fw running? cool */ | ||
445 | goto out; | ||
446 | } | ||
447 | dev_err(i1480->dev, "Timed out waiting for fw to start\n"); | ||
448 | result = -ETIMEDOUT; | ||
449 | out: | ||
450 | d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); | ||
451 | return result; | ||
452 | |||
453 | } | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Upload MAC firmware, wait for it to start | ||
458 | * | ||
459 | * @i1480: Device instance | ||
460 | * @fw_name: Name of the file that contains the firmware | ||
461 | * | ||
462 | * This has to be called after the pre fw has been uploaded (if | ||
463 | * there is any). | ||
464 | */ | ||
465 | int i1480_mac_fw_upload(struct i1480 *i1480) | ||
466 | { | ||
467 | int result = 0, deprecated_name = 0; | ||
468 | struct i1480_rceb *rcebe = (void *) i1480->evt_buf; | ||
469 | |||
470 | d_fnstart(3, i1480->dev, "(%p)\n", i1480); | ||
471 | result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC"); | ||
472 | if (result == -ENOENT) { | ||
473 | result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate, | ||
474 | "MAC"); | ||
475 | deprecated_name = 1; | ||
476 | } | ||
477 | if (result < 0) | ||
478 | return result; | ||
479 | if (deprecated_name == 1) | ||
480 | dev_warn(i1480->dev, | ||
481 | "WARNING: firmware file name %s is deprecated, " | ||
482 | "please rename to %s\n", | ||
483 | i1480->mac_fw_name_deprecate, i1480->mac_fw_name); | ||
484 | result = i1480_fw_is_running_q(i1480); | ||
485 | if (result < 0) | ||
486 | goto error_fw_not_running; | ||
487 | result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0; | ||
488 | if (result < 0) { | ||
489 | dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n", | ||
490 | result); | ||
491 | goto error_setup; | ||
492 | } | ||
493 | result = i1480->wait_init_done(i1480); /* wait init'on */ | ||
494 | if (result < 0) { | ||
495 | dev_err(i1480->dev, "MAC fw '%s': Initialization timed out " | ||
496 | "(%d)\n", i1480->mac_fw_name, result); | ||
497 | goto error_init_timeout; | ||
498 | } | ||
499 | /* verify we got the right initialization done event */ | ||
500 | if (i1480->evt_result != sizeof(*rcebe)) { | ||
501 | dev_err(i1480->dev, "MAC fw '%s': initialization event returns " | ||
502 | "wrong size (%zu bytes vs %zu needed)\n", | ||
503 | i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe)); | ||
504 | dump_bytes(i1480->dev, rcebe, min(i1480->evt_result, (ssize_t)32)); | ||
505 | goto error_size; | ||
506 | } | ||
507 | result = -EIO; | ||
508 | if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1, | ||
509 | i1480_EVT_RM_INIT_DONE) < 0) { | ||
510 | dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x " | ||
511 | "received; expected 0x%02x/%04x/00\n", | ||
512 | rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent), | ||
513 | rcebe->rceb.bEventContext, i1480_CET_VS1, | ||
514 | i1480_EVT_RM_INIT_DONE); | ||
515 | goto error_init_timeout; | ||
516 | } | ||
517 | result = i1480_cmd_reset(i1480); | ||
518 | if (result < 0) | ||
519 | dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n", | ||
520 | i1480->mac_fw_name, result); | ||
521 | error_fw_not_running: | ||
522 | error_init_timeout: | ||
523 | error_size: | ||
524 | error_setup: | ||
525 | d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); | ||
526 | return result; | ||
527 | } | ||
diff --git a/drivers/uwb/i1480/dfu/phy.c b/drivers/uwb/i1480/dfu/phy.c new file mode 100644 index 000000000000..3b1a87de8e63 --- /dev/null +++ b/drivers/uwb/i1480/dfu/phy.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * PHY parameters upload | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Code for uploading the PHY parameters to the PHY through the UWB | ||
24 | * Radio Control interface. | ||
25 | * | ||
26 | * We just send the data through the MPI interface using HWA-like | ||
27 | * commands and then reset the PHY to make sure it is ok. | ||
28 | */ | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/usb/wusb.h> | ||
33 | #include "i1480-dfu.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Write a value array to an address of the MPI interface | ||
38 | * | ||
39 | * @i1480: Device descriptor | ||
40 | * @data: Data array to write | ||
41 | * @size: Size of the data array | ||
42 | * @returns: 0 if ok, < 0 errno code on error. | ||
43 | * | ||
44 | * The data array is organized into pairs: | ||
45 | * | ||
46 | * ADDRESS VALUE | ||
47 | * | ||
48 | * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has | ||
49 | * to be a multiple of three. | ||
50 | */ | ||
51 | static | ||
52 | int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size) | ||
53 | { | ||
54 | int result; | ||
55 | struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf; | ||
56 | struct i1480_evt_confirm *reply = i1480->evt_buf; | ||
57 | |||
58 | BUG_ON(size > 480); | ||
59 | result = -ENOMEM; | ||
60 | cmd->rccb.bCommandType = i1480_CET_VS1; | ||
61 | cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE); | ||
62 | cmd->size = cpu_to_le16(size); | ||
63 | memcpy(cmd->data, data, size); | ||
64 | reply->rceb.bEventType = i1480_CET_VS1; | ||
65 | reply->rceb.wEvent = i1480_CMD_MPI_WRITE; | ||
66 | result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply)); | ||
67 | if (result < 0) | ||
68 | goto out; | ||
69 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
70 | dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n", | ||
71 | reply->bResultCode); | ||
72 | result = -EIO; | ||
73 | } | ||
74 | out: | ||
75 | return result; | ||
76 | } | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Read a value array to from an address of the MPI interface | ||
81 | * | ||
82 | * @i1480: Device descriptor | ||
83 | * @data: where to place the read array | ||
84 | * @srcaddr: Where to read from | ||
85 | * @size: Size of the data read array | ||
86 | * @returns: 0 if ok, < 0 errno code on error. | ||
87 | * | ||
88 | * The command data array is organized into pairs ADDR0 ADDR1..., and | ||
89 | * the returned data in ADDR0 VALUE0 ADDR1 VALUE1... | ||
90 | * | ||
91 | * We generate the command array to be a sequential read and then | ||
92 | * rearrange the result. | ||
93 | * | ||
94 | * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply. | ||
95 | * | ||
96 | * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount | ||
97 | * of values we can read is (512 - sizeof(*reply)) / 3 | ||
98 | */ | ||
99 | static | ||
100 | int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size) | ||
101 | { | ||
102 | int result; | ||
103 | struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf; | ||
104 | struct i1480_evt_mpi_read *reply = i1480->evt_buf; | ||
105 | unsigned cnt; | ||
106 | |||
107 | memset(i1480->cmd_buf, 0x69, 512); | ||
108 | memset(i1480->evt_buf, 0x69, 512); | ||
109 | |||
110 | BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3); | ||
111 | result = -ENOMEM; | ||
112 | cmd->rccb.bCommandType = i1480_CET_VS1; | ||
113 | cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ); | ||
114 | cmd->size = cpu_to_le16(3*size); | ||
115 | for (cnt = 0; cnt < size; cnt++) { | ||
116 | cmd->data[cnt].page = (srcaddr + cnt) >> 8; | ||
117 | cmd->data[cnt].offset = (srcaddr + cnt) & 0xff; | ||
118 | } | ||
119 | reply->rceb.bEventType = i1480_CET_VS1; | ||
120 | reply->rceb.wEvent = i1480_CMD_MPI_READ; | ||
121 | result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size, | ||
122 | sizeof(*reply) + 3*size); | ||
123 | if (result < 0) | ||
124 | goto out; | ||
125 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
126 | dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n", | ||
127 | reply->bResultCode); | ||
128 | result = -EIO; | ||
129 | } | ||
130 | for (cnt = 0; cnt < size; cnt++) { | ||
131 | if (reply->data[cnt].page != (srcaddr + cnt) >> 8) | ||
132 | dev_err(i1480->dev, "MPI-READ: page inconsistency at " | ||
133 | "index %u: expected 0x%02x, got 0x%02x\n", cnt, | ||
134 | (srcaddr + cnt) >> 8, reply->data[cnt].page); | ||
135 | if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff)) | ||
136 | dev_err(i1480->dev, "MPI-READ: offset inconsistency at " | ||
137 | "index %u: expected 0x%02x, got 0x%02x\n", cnt, | ||
138 | (srcaddr + cnt) & 0x00ff, | ||
139 | reply->data[cnt].offset); | ||
140 | data[cnt] = reply->data[cnt].value; | ||
141 | } | ||
142 | result = 0; | ||
143 | out: | ||
144 | return result; | ||
145 | } | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Upload a PHY firmware, wait for it to start | ||
150 | * | ||
151 | * @i1480: Device instance | ||
152 | * @fw_name: Name of the file that contains the firmware | ||
153 | * | ||
154 | * We assume the MAC fw is up and running. This means we can use the | ||
155 | * MPI interface to write the PHY firmware. Once done, we issue an | ||
156 | * MBOA Reset, which will force the MAC to reset and reinitialize the | ||
157 | * PHY. If that works, we are ready to go. | ||
158 | * | ||
159 | * Max packet size for the MPI write is 512, so the max buffer is 480 | ||
160 | * (which gives us 160 byte triads of MSB, LSB and VAL for the data). | ||
161 | */ | ||
162 | int i1480_phy_fw_upload(struct i1480 *i1480) | ||
163 | { | ||
164 | int result; | ||
165 | const struct firmware *fw; | ||
166 | const char *data_itr, *data_top; | ||
167 | const size_t MAX_BLK_SIZE = 480; /* 160 triads */ | ||
168 | size_t data_size; | ||
169 | u8 phy_stat; | ||
170 | |||
171 | result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev); | ||
172 | if (result < 0) | ||
173 | goto out; | ||
174 | /* Loop writing data in chunks as big as possible until done. */ | ||
175 | for (data_itr = fw->data, data_top = data_itr + fw->size; | ||
176 | data_itr < data_top; data_itr += MAX_BLK_SIZE) { | ||
177 | data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr)); | ||
178 | result = i1480_mpi_write(i1480, data_itr, data_size); | ||
179 | if (result < 0) | ||
180 | goto error_mpi_write; | ||
181 | } | ||
182 | /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */ | ||
183 | result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1); | ||
184 | if (result < 0) { | ||
185 | dev_err(i1480->dev, "PHY: can't get status: %d\n", result); | ||
186 | goto error_mpi_status; | ||
187 | } | ||
188 | if (phy_stat != 0) { | ||
189 | result = -ENODEV; | ||
190 | dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat); | ||
191 | goto error_phy_status; | ||
192 | } | ||
193 | dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name); | ||
194 | error_phy_status: | ||
195 | error_mpi_status: | ||
196 | error_mpi_write: | ||
197 | release_firmware(fw); | ||
198 | if (result < 0) | ||
199 | dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), " | ||
200 | "power cycle device\n", i1480->phy_fw_name, result); | ||
201 | out: | ||
202 | return result; | ||
203 | } | ||
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c new file mode 100644 index 000000000000..98eeeff051aa --- /dev/null +++ b/drivers/uwb/i1480/dfu/usb.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * USB SKU firmware upload implementation | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This driver will prepare the i1480 device to behave as a real | ||
24 | * Wireless USB HWA adaptor by uploading the firmware. | ||
25 | * | ||
26 | * When the device is connected or driver is loaded, i1480_usb_probe() | ||
27 | * is called--this will allocate and initialize the device structure, | ||
28 | * fill in the pointers to the common functions (read, write, | ||
29 | * wait_init_done and cmd for HWA command execution) and once that is | ||
30 | * done, call the common firmware uploading routine. Then clean up and | ||
31 | * return -ENODEV, as we don't attach to the device. | ||
32 | * | ||
33 | * The rest are the basic ops we implement that the fw upload code | ||
34 | * uses to do its job. All the ops in the common code are i1480->NAME, | ||
35 | * the functions are i1480_usb_NAME(). | ||
36 | */ | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/version.h> | ||
39 | #include <linux/usb.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/uwb.h> | ||
43 | #include <linux/usb/wusb.h> | ||
44 | #include <linux/usb/wusb-wa.h> | ||
45 | #include "i1480-dfu.h" | ||
46 | |||
47 | #define D_LOCAL 0 | ||
48 | #include <linux/uwb/debug.h> | ||
49 | |||
50 | |||
51 | struct i1480_usb { | ||
52 | struct i1480 i1480; | ||
53 | struct usb_device *usb_dev; | ||
54 | struct usb_interface *usb_iface; | ||
55 | struct urb *neep_urb; /* URB for reading from EP1 */ | ||
56 | }; | ||
57 | |||
58 | |||
59 | static | ||
60 | void i1480_usb_init(struct i1480_usb *i1480_usb) | ||
61 | { | ||
62 | i1480_init(&i1480_usb->i1480); | ||
63 | } | ||
64 | |||
65 | |||
66 | static | ||
67 | int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface) | ||
68 | { | ||
69 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
70 | int result = -ENOMEM; | ||
71 | |||
72 | i1480_usb->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ | ||
73 | i1480_usb->usb_iface = usb_get_intf(iface); | ||
74 | usb_set_intfdata(iface, i1480_usb); /* Bind the driver to iface0 */ | ||
75 | i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
76 | if (i1480_usb->neep_urb == NULL) | ||
77 | goto error; | ||
78 | return 0; | ||
79 | |||
80 | error: | ||
81 | usb_set_intfdata(iface, NULL); | ||
82 | usb_put_intf(iface); | ||
83 | usb_put_dev(usb_dev); | ||
84 | return result; | ||
85 | } | ||
86 | |||
87 | |||
88 | static | ||
89 | void i1480_usb_destroy(struct i1480_usb *i1480_usb) | ||
90 | { | ||
91 | usb_kill_urb(i1480_usb->neep_urb); | ||
92 | usb_free_urb(i1480_usb->neep_urb); | ||
93 | usb_set_intfdata(i1480_usb->usb_iface, NULL); | ||
94 | usb_put_intf(i1480_usb->usb_iface); | ||
95 | usb_put_dev(i1480_usb->usb_dev); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Write a buffer to a memory address in the i1480 device | ||
101 | * | ||
102 | * @i1480: i1480 instance | ||
103 | * @memory_address: | ||
104 | * Address where to write the data buffer to. | ||
105 | * @buffer: Buffer to the data | ||
106 | * @size: Size of the buffer [has to be < 512]. | ||
107 | * @returns: 0 if ok, < 0 errno code on error. | ||
108 | * | ||
109 | * Data buffers to USB cannot be on the stack or in vmalloc'ed areas, | ||
110 | * so we copy it to the local i1480 buffer before proceeding. In any | ||
111 | * case, we have a max size we can send, soooo. | ||
112 | */ | ||
113 | static | ||
114 | int i1480_usb_write(struct i1480 *i1480, u32 memory_address, | ||
115 | const void *buffer, size_t size) | ||
116 | { | ||
117 | int result = 0; | ||
118 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
119 | size_t buffer_size, itr = 0; | ||
120 | |||
121 | d_fnstart(3, i1480->dev, "(%p, 0x%08x, %p, %zu)\n", | ||
122 | i1480, memory_address, buffer, size); | ||
123 | BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ | ||
124 | while (size > 0) { | ||
125 | buffer_size = size < i1480->buf_size ? size : i1480->buf_size; | ||
126 | memcpy(i1480->cmd_buf, buffer + itr, buffer_size); | ||
127 | result = usb_control_msg( | ||
128 | i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), | ||
129 | 0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
130 | cpu_to_le16(memory_address & 0xffff), | ||
131 | cpu_to_le16((memory_address >> 16) & 0xffff), | ||
132 | i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */); | ||
133 | if (result < 0) | ||
134 | break; | ||
135 | d_printf(3, i1480->dev, | ||
136 | "wrote @ 0x%08x %u bytes (of %zu bytes requested)\n", | ||
137 | memory_address, result, buffer_size); | ||
138 | d_dump(4, i1480->dev, i1480->cmd_buf, result); | ||
139 | itr += result; | ||
140 | memory_address += result; | ||
141 | size -= result; | ||
142 | } | ||
143 | d_fnend(3, i1480->dev, "(%p, 0x%08x, %p, %zu) = %d\n", | ||
144 | i1480, memory_address, buffer, size, result); | ||
145 | return result; | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Read a block [max size 512] of the device's memory to @i1480's buffer. | ||
151 | * | ||
152 | * @i1480: i1480 instance | ||
153 | * @memory_address: | ||
154 | * Address where to read from. | ||
155 | * @size: Size to read. Smaller than or equal to 512. | ||
156 | * @returns: >= 0 number of bytes written if ok, < 0 errno code on error. | ||
157 | * | ||
158 | * NOTE: if the memory address or block is incorrect, you might get a | ||
159 | * stall or a different memory read. Caller has to verify the | ||
160 | * memory address and size passed back in the @neh structure. | ||
161 | */ | ||
162 | static | ||
163 | int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size) | ||
164 | { | ||
165 | ssize_t result = 0, bytes = 0; | ||
166 | size_t itr, read_size = i1480->buf_size; | ||
167 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
168 | |||
169 | d_fnstart(3, i1480->dev, "(%p, 0x%08x, %zu)\n", | ||
170 | i1480, addr, size); | ||
171 | BUG_ON(size > i1480->buf_size); | ||
172 | BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ | ||
173 | BUG_ON(read_size > 512); | ||
174 | |||
175 | if (addr >= 0x8000d200 && addr < 0x8000d400) /* Yeah, HW quirk */ | ||
176 | read_size = 4; | ||
177 | |||
178 | for (itr = 0; itr < size; itr += read_size) { | ||
179 | size_t itr_addr = addr + itr; | ||
180 | size_t itr_size = min(read_size, size - itr); | ||
181 | result = usb_control_msg( | ||
182 | i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0), | ||
183 | 0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
184 | cpu_to_le16(itr_addr & 0xffff), | ||
185 | cpu_to_le16((itr_addr >> 16) & 0xffff), | ||
186 | i1480->cmd_buf + itr, itr_size, | ||
187 | 100 /* FIXME: arbitrary */); | ||
188 | if (result < 0) { | ||
189 | dev_err(i1480->dev, "%s: USB read error: %zd\n", | ||
190 | __func__, result); | ||
191 | goto out; | ||
192 | } | ||
193 | if (result != itr_size) { | ||
194 | result = -EIO; | ||
195 | dev_err(i1480->dev, | ||
196 | "%s: partial read got only %zu bytes vs %zu expected\n", | ||
197 | __func__, result, itr_size); | ||
198 | goto out; | ||
199 | } | ||
200 | bytes += result; | ||
201 | } | ||
202 | result = bytes; | ||
203 | out: | ||
204 | d_fnend(3, i1480->dev, "(%p, 0x%08x, %zu) = %zd\n", | ||
205 | i1480, addr, size, result); | ||
206 | if (result > 0) | ||
207 | d_dump(4, i1480->dev, i1480->cmd_buf, result); | ||
208 | return result; | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Callback for reads on the notification/event endpoint | ||
214 | * | ||
215 | * Just enables the completion read handler. | ||
216 | */ | ||
217 | static | ||
218 | void i1480_usb_neep_cb(struct urb *urb) | ||
219 | { | ||
220 | struct i1480 *i1480 = urb->context; | ||
221 | struct device *dev = i1480->dev; | ||
222 | |||
223 | switch (urb->status) { | ||
224 | case 0: | ||
225 | break; | ||
226 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
227 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
228 | dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status); | ||
229 | break; | ||
230 | case -ESHUTDOWN: /* going away! */ | ||
231 | dev_dbg(dev, "NEEP: down %d\n", urb->status); | ||
232 | break; | ||
233 | default: | ||
234 | dev_err(dev, "NEEP: unknown status %d\n", urb->status); | ||
235 | break; | ||
236 | } | ||
237 | i1480->evt_result = urb->actual_length; | ||
238 | complete(&i1480->evt_complete); | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Wait for the MAC FW to initialize | ||
245 | * | ||
246 | * MAC FW sends a 0xfd/0101/00 notification to EP1 when done | ||
247 | * initializing. Get that notification into i1480->evt_buf; upper layer | ||
248 | * will verify it. | ||
249 | * | ||
250 | * Set i1480->evt_result with the result of getting the event or its | ||
251 | * size (if succesful). | ||
252 | * | ||
253 | * Delivers the data directly to i1480->evt_buf | ||
254 | */ | ||
255 | static | ||
256 | int i1480_usb_wait_init_done(struct i1480 *i1480) | ||
257 | { | ||
258 | int result; | ||
259 | struct device *dev = i1480->dev; | ||
260 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
261 | struct usb_endpoint_descriptor *epd; | ||
262 | |||
263 | d_fnstart(3, dev, "(%p)\n", i1480); | ||
264 | init_completion(&i1480->evt_complete); | ||
265 | i1480->evt_result = -EINPROGRESS; | ||
266 | epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; | ||
267 | usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev, | ||
268 | usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), | ||
269 | i1480->evt_buf, i1480->buf_size, | ||
270 | i1480_usb_neep_cb, i1480, epd->bInterval); | ||
271 | result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); | ||
272 | if (result < 0) { | ||
273 | dev_err(dev, "init done: cannot submit NEEP read: %d\n", | ||
274 | result); | ||
275 | goto error_submit; | ||
276 | } | ||
277 | /* Wait for the USB callback to get the data */ | ||
278 | result = wait_for_completion_interruptible_timeout( | ||
279 | &i1480->evt_complete, HZ); | ||
280 | if (result <= 0) { | ||
281 | result = result == 0 ? -ETIMEDOUT : result; | ||
282 | goto error_wait; | ||
283 | } | ||
284 | usb_kill_urb(i1480_usb->neep_urb); | ||
285 | d_fnend(3, dev, "(%p) = 0\n", i1480); | ||
286 | return 0; | ||
287 | |||
288 | error_wait: | ||
289 | usb_kill_urb(i1480_usb->neep_urb); | ||
290 | error_submit: | ||
291 | i1480->evt_result = result; | ||
292 | d_fnend(3, dev, "(%p) = %d\n", i1480, result); | ||
293 | return result; | ||
294 | } | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Generic function for issuing commands to the i1480 | ||
299 | * | ||
300 | * @i1480: i1480 instance | ||
301 | * @cmd_name: Name of the command (for error messages) | ||
302 | * @cmd: Pointer to command buffer | ||
303 | * @cmd_size: Size of the command buffer | ||
304 | * @reply: Buffer for the reply event | ||
305 | * @reply_size: Expected size back (including RCEB); the reply buffer | ||
306 | * is assumed to be as big as this. | ||
307 | * @returns: >= 0 size of the returned event data if ok, | ||
308 | * < 0 errno code on error. | ||
309 | * | ||
310 | * Arms the NE handle, issues the command to the device and checks the | ||
311 | * basics of the reply event. | ||
312 | */ | ||
313 | static | ||
314 | int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size) | ||
315 | { | ||
316 | int result; | ||
317 | struct device *dev = i1480->dev; | ||
318 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
319 | struct usb_endpoint_descriptor *epd; | ||
320 | struct uwb_rccb *cmd = i1480->cmd_buf; | ||
321 | u8 iface_no; | ||
322 | |||
323 | d_fnstart(3, dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); | ||
324 | /* Post a read on the notification & event endpoint */ | ||
325 | iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
326 | epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; | ||
327 | usb_fill_int_urb( | ||
328 | i1480_usb->neep_urb, i1480_usb->usb_dev, | ||
329 | usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), | ||
330 | i1480->evt_buf, i1480->buf_size, | ||
331 | i1480_usb_neep_cb, i1480, epd->bInterval); | ||
332 | result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); | ||
333 | if (result < 0) { | ||
334 | dev_err(dev, "%s: cannot submit NEEP read: %d\n", | ||
335 | cmd_name, result); | ||
336 | goto error_submit_ep1; | ||
337 | } | ||
338 | /* Now post the command on EP0 */ | ||
339 | result = usb_control_msg( | ||
340 | i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), | ||
341 | WA_EXEC_RC_CMD, | ||
342 | USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, | ||
343 | 0, iface_no, | ||
344 | cmd, cmd_size, | ||
345 | 100 /* FIXME: this is totally arbitrary */); | ||
346 | if (result < 0) { | ||
347 | dev_err(dev, "%s: control request failed: %d\n", | ||
348 | cmd_name, result); | ||
349 | goto error_submit_ep0; | ||
350 | } | ||
351 | d_fnend(3, dev, "(%p, %s, %zu) = %d\n", | ||
352 | i1480, cmd_name, cmd_size, result); | ||
353 | return result; | ||
354 | |||
355 | error_submit_ep0: | ||
356 | usb_kill_urb(i1480_usb->neep_urb); | ||
357 | error_submit_ep1: | ||
358 | d_fnend(3, dev, "(%p, %s, %zu) = %d\n", | ||
359 | i1480, cmd_name, cmd_size, result); | ||
360 | return result; | ||
361 | } | ||
362 | |||
363 | |||
364 | /* | ||
365 | * Probe a i1480 device for uploading firmware. | ||
366 | * | ||
367 | * We attach only to interface #0, which is the radio control interface. | ||
368 | */ | ||
369 | static | ||
370 | int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id) | ||
371 | { | ||
372 | struct i1480_usb *i1480_usb; | ||
373 | struct i1480 *i1480; | ||
374 | struct device *dev = &iface->dev; | ||
375 | int result; | ||
376 | |||
377 | result = -ENODEV; | ||
378 | if (iface->cur_altsetting->desc.bInterfaceNumber != 0) { | ||
379 | dev_dbg(dev, "not attaching to iface %d\n", | ||
380 | iface->cur_altsetting->desc.bInterfaceNumber); | ||
381 | goto error; | ||
382 | } | ||
383 | if (iface->num_altsetting > 1 | ||
384 | && interface_to_usbdev(iface)->descriptor.idProduct == 0xbabe) { | ||
385 | /* Need altsetting #1 [HW QUIRK] or EP1 won't work */ | ||
386 | result = usb_set_interface(interface_to_usbdev(iface), 0, 1); | ||
387 | if (result < 0) | ||
388 | dev_warn(dev, | ||
389 | "can't set altsetting 1 on iface 0: %d\n", | ||
390 | result); | ||
391 | } | ||
392 | |||
393 | result = -ENOMEM; | ||
394 | i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL); | ||
395 | if (i1480_usb == NULL) { | ||
396 | dev_err(dev, "Unable to allocate instance\n"); | ||
397 | goto error; | ||
398 | } | ||
399 | i1480_usb_init(i1480_usb); | ||
400 | |||
401 | i1480 = &i1480_usb->i1480; | ||
402 | i1480->buf_size = 512; | ||
403 | i1480->cmd_buf = kmalloc(2 * i1480->buf_size, GFP_KERNEL); | ||
404 | if (i1480->cmd_buf == NULL) { | ||
405 | dev_err(dev, "Cannot allocate transfer buffers\n"); | ||
406 | result = -ENOMEM; | ||
407 | goto error_buf_alloc; | ||
408 | } | ||
409 | i1480->evt_buf = i1480->cmd_buf + i1480->buf_size; | ||
410 | |||
411 | result = i1480_usb_create(i1480_usb, iface); | ||
412 | if (result < 0) { | ||
413 | dev_err(dev, "Cannot create instance: %d\n", result); | ||
414 | goto error_create; | ||
415 | } | ||
416 | |||
417 | /* setup the fops and upload the firmare */ | ||
418 | i1480->pre_fw_name = "i1480-pre-phy-0.0.bin"; | ||
419 | i1480->mac_fw_name = "i1480-usb-0.0.bin"; | ||
420 | i1480->mac_fw_name_deprecate = "ptc-0.0.bin"; | ||
421 | i1480->phy_fw_name = "i1480-phy-0.0.bin"; | ||
422 | i1480->dev = &iface->dev; | ||
423 | i1480->write = i1480_usb_write; | ||
424 | i1480->read = i1480_usb_read; | ||
425 | i1480->rc_setup = NULL; | ||
426 | i1480->wait_init_done = i1480_usb_wait_init_done; | ||
427 | i1480->cmd = i1480_usb_cmd; | ||
428 | |||
429 | result = i1480_fw_upload(&i1480_usb->i1480); /* the real thing */ | ||
430 | if (result >= 0) { | ||
431 | usb_reset_device(i1480_usb->usb_dev); | ||
432 | result = -ENODEV; /* we don't want to bind to the iface */ | ||
433 | } | ||
434 | i1480_usb_destroy(i1480_usb); | ||
435 | error_create: | ||
436 | kfree(i1480->cmd_buf); | ||
437 | error_buf_alloc: | ||
438 | kfree(i1480_usb); | ||
439 | error: | ||
440 | return result; | ||
441 | } | ||
442 | |||
443 | #define i1480_USB_DEV(v, p) \ | ||
444 | { \ | ||
445 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | ||
446 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | ||
447 | | USB_DEVICE_ID_MATCH_INT_INFO, \ | ||
448 | .idVendor = (v), \ | ||
449 | .idProduct = (p), \ | ||
450 | .bDeviceClass = 0xff, \ | ||
451 | .bDeviceSubClass = 0xff, \ | ||
452 | .bDeviceProtocol = 0xff, \ | ||
453 | .bInterfaceClass = 0xff, \ | ||
454 | .bInterfaceSubClass = 0xff, \ | ||
455 | .bInterfaceProtocol = 0xff, \ | ||
456 | } | ||
457 | |||
458 | |||
459 | /** USB device ID's that we handle */ | ||
460 | static struct usb_device_id i1480_usb_id_table[] = { | ||
461 | i1480_USB_DEV(0x8086, 0xdf3b), | ||
462 | i1480_USB_DEV(0x15a9, 0x0005), | ||
463 | i1480_USB_DEV(0x07d1, 0x3802), | ||
464 | i1480_USB_DEV(0x050d, 0x305a), | ||
465 | i1480_USB_DEV(0x3495, 0x3007), | ||
466 | {}, | ||
467 | }; | ||
468 | MODULE_DEVICE_TABLE(usb, i1480_usb_id_table); | ||
469 | |||
470 | |||
471 | static struct usb_driver i1480_dfu_driver = { | ||
472 | .name = "i1480-dfu-usb", | ||
473 | .id_table = i1480_usb_id_table, | ||
474 | .probe = i1480_usb_probe, | ||
475 | .disconnect = NULL, | ||
476 | }; | ||
477 | |||
478 | |||
479 | /* | ||
480 | * Initialize the i1480 DFU driver. | ||
481 | * | ||
482 | * We also need to register our function for guessing event sizes. | ||
483 | */ | ||
484 | static int __init i1480_dfu_driver_init(void) | ||
485 | { | ||
486 | return usb_register(&i1480_dfu_driver); | ||
487 | } | ||
488 | module_init(i1480_dfu_driver_init); | ||
489 | |||
490 | |||
491 | static void __exit i1480_dfu_driver_exit(void) | ||
492 | { | ||
493 | usb_deregister(&i1480_dfu_driver); | ||
494 | } | ||
495 | module_exit(i1480_dfu_driver_exit); | ||
496 | |||
497 | |||
498 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
499 | MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB"); | ||
500 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c new file mode 100644 index 000000000000..7bf8c6febae7 --- /dev/null +++ b/drivers/uwb/i1480/i1480-est.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * Event Size tables for Wired Adaptors | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/uwb.h> | ||
30 | #include "dfu/i1480-dfu.h" | ||
31 | |||
32 | |||
33 | /** Event size table for wEvents 0x00XX */ | ||
34 | static struct uwb_est_entry i1480_est_fd00[] = { | ||
35 | /* Anybody expecting this response has to use | ||
36 | * neh->extra_size to specify the real size that will | ||
37 | * come back. */ | ||
38 | [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) }, | ||
39 | [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) }, | ||
40 | #ifdef i1480_RCEB_EXTENDED | ||
41 | [0x09] = { | ||
42 | .size = sizeof(struct i1480_rceb), | ||
43 | .offset = 1 + offsetof(struct i1480_rceb, wParamLength), | ||
44 | }, | ||
45 | #endif | ||
46 | }; | ||
47 | |||
48 | /** Event size table for wEvents 0x01XX */ | ||
49 | static struct uwb_est_entry i1480_est_fd01[] = { | ||
50 | [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) }, | ||
51 | [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 }, | ||
52 | [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 }, | ||
53 | [0xff & i1480_EVT_DEV_ID_CHANGE] = { | ||
54 | .size = sizeof(struct i1480_rceb) + 2 }, | ||
55 | }; | ||
56 | |||
57 | static int i1480_est_init(void) | ||
58 | { | ||
59 | int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, | ||
60 | i1480_est_fd00, | ||
61 | ARRAY_SIZE(i1480_est_fd00)); | ||
62 | if (result < 0) { | ||
63 | printk(KERN_ERR "Can't register EST table fd00: %d\n", result); | ||
64 | return result; | ||
65 | } | ||
66 | result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, | ||
67 | i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); | ||
68 | if (result < 0) { | ||
69 | printk(KERN_ERR "Can't register EST table fd01: %d\n", result); | ||
70 | return result; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | module_init(i1480_est_init); | ||
75 | |||
76 | static void i1480_est_exit(void) | ||
77 | { | ||
78 | uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, | ||
79 | i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00)); | ||
80 | uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, | ||
81 | i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); | ||
82 | } | ||
83 | module_exit(i1480_est_exit); | ||
84 | |||
85 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
86 | MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables"); | ||
87 | MODULE_LICENSE("GPL"); | ||
88 | |||
89 | /** | ||
90 | * USB device ID's that we handle | ||
91 | * | ||
92 | * [so we are loaded when this kind device is connected] | ||
93 | */ | ||
94 | static struct usb_device_id i1480_est_id_table[] = { | ||
95 | { USB_DEVICE(0x8086, 0xdf3b), }, | ||
96 | { USB_DEVICE(0x8086, 0x0c3b), }, | ||
97 | { }, | ||
98 | }; | ||
99 | MODULE_DEVICE_TABLE(usb, i1480_est_id_table); | ||
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h new file mode 100644 index 000000000000..18a8b0e4567b --- /dev/null +++ b/drivers/uwb/i1480/i1480-wlp.h | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link | ||
3 | * WLP specific definitions | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * FIXME: docs | ||
25 | */ | ||
26 | |||
27 | #ifndef __i1480_wlp_h__ | ||
28 | #define __i1480_wlp_h__ | ||
29 | |||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/uwb.h> | ||
33 | #include <linux/if_ether.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | |||
36 | /* New simplified header format? */ | ||
37 | #undef WLP_HDR_FMT_2 /* FIXME: rename */ | ||
38 | |||
39 | /** | ||
40 | * Values of the Delivery ID & Type field when PCA or DRP | ||
41 | * | ||
42 | * The Delivery ID & Type field in the WLP TX header indicates whether | ||
43 | * the frame is PCA or DRP. This is done based on the high level bit of | ||
44 | * this field. | ||
45 | * We use this constant to test if the traffic is PCA or DRP as follows: | ||
46 | * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP) | ||
47 | * this is DRP traffic | ||
48 | * else | ||
49 | * this is PCA traffic | ||
50 | */ | ||
51 | enum deliver_id_type_bit { | ||
52 | WLP_DRP = 8, | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * WLP TX header | ||
57 | * | ||
58 | * Indicates UWB/WLP-specific transmission parameters for a network | ||
59 | * packet. | ||
60 | */ | ||
61 | struct wlp_tx_hdr { | ||
62 | /* dword 0 */ | ||
63 | struct uwb_dev_addr dstaddr; | ||
64 | u8 key_index; | ||
65 | u8 mac_params; | ||
66 | /* dword 1 */ | ||
67 | u8 phy_params; | ||
68 | #ifndef WLP_HDR_FMT_2 | ||
69 | u8 reserved; | ||
70 | __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */ | ||
71 | /* dword 2 */ | ||
72 | u8 oui2; /* if all LE, it could be merged */ | ||
73 | __le16 prid; | ||
74 | #endif | ||
75 | } __attribute__((packed)); | ||
76 | |||
77 | static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr) | ||
78 | { | ||
79 | return hdr->mac_params & 0x0f; | ||
80 | } | ||
81 | |||
82 | static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr) | ||
83 | { | ||
84 | return (hdr->mac_params >> 4) & 0x07; | ||
85 | } | ||
86 | |||
87 | static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr) | ||
88 | { | ||
89 | return (hdr->mac_params >> 7) & 0x01; | ||
90 | } | ||
91 | |||
92 | static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id) | ||
93 | { | ||
94 | hdr->mac_params = (hdr->mac_params & ~0x0f) | id; | ||
95 | } | ||
96 | |||
97 | static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr, | ||
98 | enum uwb_ack_pol policy) | ||
99 | { | ||
100 | hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4); | ||
101 | } | ||
102 | |||
103 | static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts) | ||
104 | { | ||
105 | hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7); | ||
106 | } | ||
107 | |||
108 | static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr) | ||
109 | { | ||
110 | return hdr->phy_params & 0x0f; | ||
111 | } | ||
112 | |||
113 | static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr) | ||
114 | { | ||
115 | return (hdr->phy_params >> 4) & 0x0f; | ||
116 | } | ||
117 | |||
118 | static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate) | ||
119 | { | ||
120 | hdr->phy_params = (hdr->phy_params & ~0x0f) | rate; | ||
121 | } | ||
122 | |||
123 | static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr) | ||
124 | { | ||
125 | hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * WLP RX header | ||
131 | * | ||
132 | * Provides UWB/WLP-specific transmission data for a received | ||
133 | * network packet. | ||
134 | */ | ||
135 | struct wlp_rx_hdr { | ||
136 | /* dword 0 */ | ||
137 | struct uwb_dev_addr dstaddr; | ||
138 | struct uwb_dev_addr srcaddr; | ||
139 | /* dword 1 */ | ||
140 | u8 LQI; | ||
141 | s8 RSSI; | ||
142 | u8 reserved3; | ||
143 | #ifndef WLP_HDR_FMT_2 | ||
144 | u8 oui0; | ||
145 | /* dword 2 */ | ||
146 | __le16 oui12; | ||
147 | __le16 prid; | ||
148 | #endif | ||
149 | } __attribute__((packed)); | ||
150 | |||
151 | |||
152 | /** User configurable options for WLP */ | ||
153 | struct wlp_options { | ||
154 | struct mutex mutex; /* access to user configurable options*/ | ||
155 | struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */ | ||
156 | u8 pca_base_priority; | ||
157 | u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/ | ||
158 | }; | ||
159 | |||
160 | |||
161 | static inline | ||
162 | void wlp_options_init(struct wlp_options *options) | ||
163 | { | ||
164 | mutex_init(&options->mutex); | ||
165 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM); | ||
166 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1); | ||
167 | /* FIXME: default to phy caps */ | ||
168 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480); | ||
169 | #ifndef WLP_HDR_FMT_2 | ||
170 | options->def_tx_hdr.prid = cpu_to_le16(0x0000); | ||
171 | #endif | ||
172 | } | ||
173 | |||
174 | |||
175 | /* sysfs helpers */ | ||
176 | |||
177 | extern ssize_t uwb_pca_base_priority_store(struct wlp_options *, | ||
178 | const char *, size_t); | ||
179 | extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *); | ||
180 | extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t); | ||
181 | extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *); | ||
182 | extern ssize_t uwb_ack_policy_store(struct wlp_options *, | ||
183 | const char *, size_t); | ||
184 | extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *); | ||
185 | extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t); | ||
186 | extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *); | ||
187 | extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t); | ||
188 | extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *); | ||
189 | |||
190 | |||
191 | /** Simple bandwidth allocation (temporary and too simple) */ | ||
192 | struct wlp_bw_allocs { | ||
193 | const char *name; | ||
194 | struct { | ||
195 | u8 mask, stream; | ||
196 | } tx, rx; | ||
197 | }; | ||
198 | |||
199 | |||
200 | #endif /* #ifndef __i1480_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile new file mode 100644 index 000000000000..fe6709b8e68b --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o | ||
2 | |||
3 | i1480u-wlp-objs := \ | ||
4 | lc.o \ | ||
5 | netdev.o \ | ||
6 | rx.o \ | ||
7 | sysfs.o \ | ||
8 | tx.o | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h new file mode 100644 index 000000000000..5f1b2951bb83 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link USB | ||
3 | * Header formats, constants, general internal interfaces | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * This is not an standard interface. | ||
25 | * | ||
26 | * FIXME: docs | ||
27 | * | ||
28 | * i1480u-wlp is pretty simple: two endpoints, one for tx, one for | ||
29 | * rx. rx is polled. Network packets (ethernet, whatever) are wrapped | ||
30 | * in i1480 TX or RX headers (for sending over the air), and these | ||
31 | * packets are wrapped in UNTD headers (for sending to the WLP UWB | ||
32 | * controller). | ||
33 | * | ||
34 | * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets | ||
35 | * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the | ||
36 | * i1480 packet is broken in chunks/packets: | ||
37 | * | ||
38 | * UNTD-1st.hdr + i1480.hdr + payload | ||
39 | * UNTD-next.hdr + payload | ||
40 | * ... | ||
41 | * UNTD-last.hdr + payload | ||
42 | * | ||
43 | * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE. | ||
44 | * | ||
45 | * All HW structures and bitmaps are little endian, so we need to play | ||
46 | * ugly tricks when defining bitfields. Hoping for the day GCC | ||
47 | * implements __attribute__((endian(1234))). | ||
48 | * | ||
49 | * FIXME: ROADMAP to the whole implementation | ||
50 | */ | ||
51 | |||
52 | #ifndef __i1480u_wlp_h__ | ||
53 | #define __i1480u_wlp_h__ | ||
54 | |||
55 | #include <linux/usb.h> | ||
56 | #include <linux/netdevice.h> | ||
57 | #include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */ | ||
58 | #include <linux/wlp.h> | ||
59 | #include "../i1480-wlp.h" | ||
60 | |||
61 | #undef i1480u_FLOW_CONTROL /* Enable flow control code */ | ||
62 | |||
63 | /** | ||
64 | * Basic flow control | ||
65 | */ | ||
66 | enum { | ||
67 | i1480u_TX_INFLIGHT_MAX = 1000, | ||
68 | i1480u_TX_INFLIGHT_THRESHOLD = 100, | ||
69 | }; | ||
70 | |||
71 | /** Maximum size of a transaction that we can tx/rx */ | ||
72 | enum { | ||
73 | /* Maximum packet size computed as follows: max UNTD header (8) + | ||
74 | * i1480 RX header (8) + max Ethernet header and payload (4096) + | ||
75 | * Padding added by skb_reserve (2) to make post Ethernet payload | ||
76 | * start on 16 byte boundary*/ | ||
77 | i1480u_MAX_RX_PKT_SIZE = 4114, | ||
78 | i1480u_MAX_FRG_SIZE = 512, | ||
79 | i1480u_RX_BUFS = 9, | ||
80 | }; | ||
81 | |||
82 | |||
83 | /** | ||
84 | * UNTD packet type | ||
85 | * | ||
86 | * We need to fragment any payload whose UNTD packet is going to be | ||
87 | * bigger than i1480u_MAX_FRG_SIZE. | ||
88 | */ | ||
89 | enum i1480u_pkt_type { | ||
90 | i1480u_PKT_FRAG_1ST = 0x1, | ||
91 | i1480u_PKT_FRAG_NXT = 0x0, | ||
92 | i1480u_PKT_FRAG_LST = 0x2, | ||
93 | i1480u_PKT_FRAG_CMP = 0x3 | ||
94 | }; | ||
95 | enum { | ||
96 | i1480u_PKT_NONE = 0x4, | ||
97 | }; | ||
98 | |||
99 | /** USB Network Transfer Descriptor - common */ | ||
100 | struct untd_hdr { | ||
101 | u8 type; | ||
102 | __le16 len; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr) | ||
106 | { | ||
107 | return hdr->type & 0x03; | ||
108 | } | ||
109 | |||
110 | static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr) | ||
111 | { | ||
112 | return (hdr->type >> 2) & 0x01; | ||
113 | } | ||
114 | |||
115 | static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type) | ||
116 | { | ||
117 | hdr->type = (hdr->type & ~0x03) | type; | ||
118 | } | ||
119 | |||
120 | static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx) | ||
121 | { | ||
122 | hdr->type = (hdr->type & ~0x04) | (rx_tx << 2); | ||
123 | } | ||
124 | |||
125 | |||
126 | /** | ||
127 | * USB Network Transfer Descriptor - Complete Packet | ||
128 | * | ||
129 | * This is for a packet that is smaller (header + payload) than | ||
130 | * i1480u_MAX_FRG_SIZE. | ||
131 | * | ||
132 | * @hdr.total_len is the size of the payload; the payload doesn't | ||
133 | * count this header nor the padding, but includes the size of i1480 | ||
134 | * header. | ||
135 | */ | ||
136 | struct untd_hdr_cmp { | ||
137 | struct untd_hdr hdr; | ||
138 | u8 padding; | ||
139 | } __attribute__((packed)); | ||
140 | |||
141 | |||
142 | /** | ||
143 | * USB Network Transfer Descriptor - First fragment | ||
144 | * | ||
145 | * @hdr.len is the size of the *whole packet* (excluding UNTD | ||
146 | * headers); @fragment_len is the size of the payload (excluding UNTD | ||
147 | * headers, but including i1480 headers). | ||
148 | */ | ||
149 | struct untd_hdr_1st { | ||
150 | struct untd_hdr hdr; | ||
151 | __le16 fragment_len; | ||
152 | u8 padding[3]; | ||
153 | } __attribute__((packed)); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * USB Network Transfer Descriptor - Next / Last [Rest] | ||
158 | * | ||
159 | * @hdr.len is the size of the payload, not including headrs. | ||
160 | */ | ||
161 | struct untd_hdr_rst { | ||
162 | struct untd_hdr hdr; | ||
163 | u8 padding; | ||
164 | } __attribute__((packed)); | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Transmission context | ||
169 | * | ||
170 | * Wraps all the stuff needed to track a pending/active tx | ||
171 | * operation. | ||
172 | */ | ||
173 | struct i1480u_tx { | ||
174 | struct list_head list_node; | ||
175 | struct i1480u *i1480u; | ||
176 | struct urb *urb; | ||
177 | |||
178 | struct sk_buff *skb; | ||
179 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
180 | |||
181 | void *buf; /* if NULL, no new buf was used */ | ||
182 | size_t buf_size; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * Basic flow control | ||
187 | * | ||
188 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
189 | * outstanding. Only allow "max" | ||
190 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
191 | * stopped. The queue will be restarted when there are | ||
192 | * "threshold" URBs outstanding. | ||
193 | * Maintain a counter of how many time the TX queue needed to be restarted | ||
194 | * due to the "max" being exceeded and the "threshold" reached again. The | ||
195 | * timestamp "restart_ts" is to keep track from when the counter was last | ||
196 | * queried (see sysfs handling of file wlp_tx_inflight). | ||
197 | */ | ||
198 | struct i1480u_tx_inflight { | ||
199 | atomic_t count; | ||
200 | unsigned long max; | ||
201 | unsigned long threshold; | ||
202 | unsigned long restart_ts; | ||
203 | atomic_t restart_count; | ||
204 | }; | ||
205 | |||
206 | /** | ||
207 | * Instance of a i1480u WLP interface | ||
208 | * | ||
209 | * Keeps references to the USB device that wraps it, as well as it's | ||
210 | * interface and associated UWB host controller. As well, it also | ||
211 | * keeps a link to the netdevice for integration into the networking | ||
212 | * stack. | ||
213 | * We maintian separate error history for the tx and rx endpoints because | ||
214 | * the implementation does not rely on locking - having one shared | ||
215 | * structure between endpoints may cause problems. Adding locking to the | ||
216 | * implementation will have higher cost than adding a separate structure. | ||
217 | */ | ||
218 | struct i1480u { | ||
219 | struct usb_device *usb_dev; | ||
220 | struct usb_interface *usb_iface; | ||
221 | struct net_device *net_dev; | ||
222 | |||
223 | spinlock_t lock; | ||
224 | struct net_device_stats stats; | ||
225 | |||
226 | /* RX context handling */ | ||
227 | struct sk_buff *rx_skb; | ||
228 | struct uwb_dev_addr rx_srcaddr; | ||
229 | size_t rx_untd_pkt_size; | ||
230 | struct i1480u_rx_buf { | ||
231 | struct i1480u *i1480u; /* back pointer */ | ||
232 | struct urb *urb; | ||
233 | struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */ | ||
234 | } rx_buf[i1480u_RX_BUFS]; /* N bufs */ | ||
235 | |||
236 | spinlock_t tx_list_lock; /* TX context */ | ||
237 | struct list_head tx_list; | ||
238 | u8 tx_stream; | ||
239 | |||
240 | struct stats lqe_stats, rssi_stats; /* radio statistics */ | ||
241 | |||
242 | /* Options we can set from sysfs */ | ||
243 | struct wlp_options options; | ||
244 | struct uwb_notifs_handler uwb_notifs_handler; | ||
245 | struct edc tx_errors; | ||
246 | struct edc rx_errors; | ||
247 | struct wlp wlp; | ||
248 | #ifdef i1480u_FLOW_CONTROL | ||
249 | struct urb *notif_urb; | ||
250 | struct edc notif_edc; /* error density counter */ | ||
251 | u8 notif_buffer[1]; | ||
252 | #endif | ||
253 | struct i1480u_tx_inflight tx_inflight; | ||
254 | }; | ||
255 | |||
256 | /* Internal interfaces */ | ||
257 | extern void i1480u_rx_cb(struct urb *urb); | ||
258 | extern int i1480u_rx_setup(struct i1480u *); | ||
259 | extern void i1480u_rx_release(struct i1480u *); | ||
260 | extern void i1480u_tx_release(struct i1480u *); | ||
261 | extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *, | ||
262 | struct uwb_dev_addr *); | ||
263 | extern void i1480u_stop_queue(struct wlp *); | ||
264 | extern void i1480u_start_queue(struct wlp *); | ||
265 | extern int i1480u_sysfs_setup(struct i1480u *); | ||
266 | extern void i1480u_sysfs_release(struct i1480u *); | ||
267 | |||
268 | /* netdev interface */ | ||
269 | extern int i1480u_open(struct net_device *); | ||
270 | extern int i1480u_stop(struct net_device *); | ||
271 | extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *); | ||
272 | extern void i1480u_tx_timeout(struct net_device *); | ||
273 | extern int i1480u_set_config(struct net_device *, struct ifmap *); | ||
274 | extern struct net_device_stats *i1480u_get_stats(struct net_device *); | ||
275 | extern int i1480u_change_mtu(struct net_device *, int); | ||
276 | extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); | ||
277 | |||
278 | /* bandwidth allocation callback */ | ||
279 | extern void i1480u_bw_alloc_cb(struct uwb_rsv *); | ||
280 | |||
281 | /* Sys FS */ | ||
282 | extern struct attribute_group i1480u_wlp_attr_group; | ||
283 | |||
284 | #endif /* #ifndef __i1480u_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c new file mode 100644 index 000000000000..737d60cd5b73 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/lc.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * This implements a very simple network driver for the WLP USB | ||
26 | * device that is associated to a UWB (Ultra Wide Band) host. | ||
27 | * | ||
28 | * This is seen as an interface of a composite device. Once the UWB | ||
29 | * host has an association to another WLP capable device, the | ||
30 | * networking interface (aka WLP) can start to send packets back and | ||
31 | * forth. | ||
32 | * | ||
33 | * Limitations: | ||
34 | * | ||
35 | * - Hand cranked; can't ifup the interface until there is an association | ||
36 | * | ||
37 | * - BW allocation very simplistic [see i1480u_mas_set() and callees]. | ||
38 | * | ||
39 | * | ||
40 | * ROADMAP: | ||
41 | * | ||
42 | * ENTRY POINTS (driver model): | ||
43 | * | ||
44 | * i1480u_driver_{exit,init}(): initialization of the driver. | ||
45 | * | ||
46 | * i1480u_probe(): called by the driver code when a device | ||
47 | * matching 'i1480u_id_table' is connected. | ||
48 | * | ||
49 | * This allocs a netdev instance, inits with | ||
50 | * i1480u_add(), then registers_netdev(). | ||
51 | * i1480u_init() | ||
52 | * i1480u_add() | ||
53 | * | ||
54 | * i1480u_disconnect(): device has been disconnected/module | ||
55 | * is being removed. | ||
56 | * i1480u_rm() | ||
57 | */ | ||
58 | #include <linux/version.h> | ||
59 | #include <linux/if_arp.h> | ||
60 | #include <linux/etherdevice.h> | ||
61 | #include <linux/uwb/debug.h> | ||
62 | #include "i1480u-wlp.h" | ||
63 | |||
64 | |||
65 | |||
66 | static inline | ||
67 | void i1480u_init(struct i1480u *i1480u) | ||
68 | { | ||
69 | /* nothing so far... doesn't it suck? */ | ||
70 | spin_lock_init(&i1480u->lock); | ||
71 | INIT_LIST_HEAD(&i1480u->tx_list); | ||
72 | spin_lock_init(&i1480u->tx_list_lock); | ||
73 | wlp_options_init(&i1480u->options); | ||
74 | edc_init(&i1480u->tx_errors); | ||
75 | edc_init(&i1480u->rx_errors); | ||
76 | #ifdef i1480u_FLOW_CONTROL | ||
77 | edc_init(&i1480u->notif_edc); | ||
78 | #endif | ||
79 | stats_init(&i1480u->lqe_stats); | ||
80 | stats_init(&i1480u->rssi_stats); | ||
81 | wlp_init(&i1480u->wlp); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Fill WLP device information structure | ||
86 | * | ||
87 | * The structure will contain a few character arrays, each ending with a | ||
88 | * null terminated string. Each string has to fit (excluding terminating | ||
89 | * character) into a specified range obtained from the WLP substack. | ||
90 | * | ||
91 | * It is still not clear exactly how this device information should be | ||
92 | * obtained. Until we find out we use the USB device descriptor as backup, some | ||
93 | * information elements have intuitive mappings, other not. | ||
94 | */ | ||
95 | static | ||
96 | void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info) | ||
97 | { | ||
98 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
99 | struct usb_device *usb_dev = i1480u->usb_dev; | ||
100 | /* Treat device name and model name the same */ | ||
101 | if (usb_dev->descriptor.iProduct) { | ||
102 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
103 | dev_info->name, sizeof(dev_info->name)); | ||
104 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
105 | dev_info->model_name, sizeof(dev_info->model_name)); | ||
106 | } | ||
107 | if (usb_dev->descriptor.iManufacturer) | ||
108 | usb_string(usb_dev, usb_dev->descriptor.iManufacturer, | ||
109 | dev_info->manufacturer, | ||
110 | sizeof(dev_info->manufacturer)); | ||
111 | scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x", | ||
112 | __le16_to_cpu(usb_dev->descriptor.bcdDevice)); | ||
113 | if (usb_dev->descriptor.iSerialNumber) | ||
114 | usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, | ||
115 | dev_info->serial, sizeof(dev_info->serial)); | ||
116 | /* FIXME: where should we obtain category? */ | ||
117 | dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER); | ||
118 | /* FIXME: Complete OUI and OUIsubdiv attributes */ | ||
119 | } | ||
120 | |||
121 | #ifdef i1480u_FLOW_CONTROL | ||
122 | /** | ||
123 | * Callback for the notification endpoint | ||
124 | * | ||
125 | * This mostly controls the xon/xoff protocol. In case of hard error, | ||
126 | * we stop the queue. If not, we always retry. | ||
127 | */ | ||
128 | static | ||
129 | void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs) | ||
130 | { | ||
131 | struct i1480u *i1480u = urb->context; | ||
132 | struct usb_interface *usb_iface = i1480u->usb_iface; | ||
133 | struct device *dev = &usb_iface->dev; | ||
134 | int result; | ||
135 | |||
136 | switch (urb->status) { | ||
137 | case 0: /* Got valid data, do xon/xoff */ | ||
138 | switch (i1480u->notif_buffer[0]) { | ||
139 | case 'N': | ||
140 | dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies); | ||
141 | netif_stop_queue(i1480u->net_dev); | ||
142 | break; | ||
143 | case 'A': | ||
144 | dev_err(dev, "XON STARTING queue at %lu\n", jiffies); | ||
145 | netif_start_queue(i1480u->net_dev); | ||
146 | break; | ||
147 | default: | ||
148 | dev_err(dev, "NEP: unknown data 0x%02hhx\n", | ||
149 | i1480u->notif_buffer[0]); | ||
150 | } | ||
151 | break; | ||
152 | case -ECONNRESET: /* Controlled situation ... */ | ||
153 | case -ENOENT: /* we killed the URB... */ | ||
154 | dev_err(dev, "NEP: URB reset/noent %d\n", urb->status); | ||
155 | goto error; | ||
156 | case -ESHUTDOWN: /* going away! */ | ||
157 | dev_err(dev, "NEP: URB down %d\n", urb->status); | ||
158 | goto error; | ||
159 | default: /* Retry unless it gets ugly */ | ||
160 | if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS, | ||
161 | EDC_ERROR_TIMEFRAME)) { | ||
162 | dev_err(dev, "NEP: URB max acceptable errors " | ||
163 | "exceeded; resetting device\n"); | ||
164 | goto error_reset; | ||
165 | } | ||
166 | dev_err(dev, "NEP: URB error %d\n", urb->status); | ||
167 | break; | ||
168 | } | ||
169 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
170 | if (result < 0) { | ||
171 | dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n", | ||
172 | result); | ||
173 | goto error_reset; | ||
174 | } | ||
175 | return; | ||
176 | |||
177 | error_reset: | ||
178 | wlp_reset_all(&i1480-wlp); | ||
179 | error: | ||
180 | netif_stop_queue(i1480u->net_dev); | ||
181 | return; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | static | ||
186 | int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) | ||
187 | { | ||
188 | int result = -ENODEV; | ||
189 | struct wlp *wlp = &i1480u->wlp; | ||
190 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
191 | struct net_device *net_dev = i1480u->net_dev; | ||
192 | struct uwb_rc *rc; | ||
193 | struct uwb_dev *uwb_dev; | ||
194 | #ifdef i1480u_FLOW_CONTROL | ||
195 | struct usb_endpoint_descriptor *epd; | ||
196 | #endif | ||
197 | |||
198 | i1480u->usb_dev = usb_get_dev(usb_dev); | ||
199 | i1480u->usb_iface = iface; | ||
200 | rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); | ||
201 | if (rc == NULL) { | ||
202 | dev_err(&iface->dev, "Cannot get associated UWB Radio " | ||
203 | "Controller\n"); | ||
204 | goto out; | ||
205 | } | ||
206 | wlp->xmit_frame = i1480u_xmit_frame; | ||
207 | wlp->fill_device_info = i1480u_fill_device_info; | ||
208 | wlp->stop_queue = i1480u_stop_queue; | ||
209 | wlp->start_queue = i1480u_start_queue; | ||
210 | result = wlp_setup(wlp, rc); | ||
211 | if (result < 0) { | ||
212 | dev_err(&iface->dev, "Cannot setup WLP\n"); | ||
213 | goto error_wlp_setup; | ||
214 | } | ||
215 | result = 0; | ||
216 | ether_setup(net_dev); /* make it an etherdevice */ | ||
217 | uwb_dev = &rc->uwb_dev; | ||
218 | /* FIXME: hookup address change notifications? */ | ||
219 | |||
220 | memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, | ||
221 | sizeof(net_dev->dev_addr)); | ||
222 | |||
223 | net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) | ||
224 | + sizeof(struct wlp_tx_hdr) | ||
225 | + WLP_DATA_HLEN | ||
226 | + ETH_HLEN; | ||
227 | net_dev->mtu = 3500; | ||
228 | net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ | ||
229 | |||
230 | /* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ | ||
231 | /* FIXME: multicast disabled */ | ||
232 | net_dev->flags &= ~IFF_MULTICAST; | ||
233 | net_dev->features &= ~NETIF_F_SG; | ||
234 | net_dev->features &= ~NETIF_F_FRAGLIST; | ||
235 | /* All NETIF_F_*_CSUM disabled */ | ||
236 | net_dev->features |= NETIF_F_HIGHDMA; | ||
237 | net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ | ||
238 | |||
239 | net_dev->open = i1480u_open; | ||
240 | net_dev->stop = i1480u_stop; | ||
241 | net_dev->hard_start_xmit = i1480u_hard_start_xmit; | ||
242 | net_dev->tx_timeout = i1480u_tx_timeout; | ||
243 | net_dev->get_stats = i1480u_get_stats; | ||
244 | net_dev->set_config = i1480u_set_config; | ||
245 | net_dev->change_mtu = i1480u_change_mtu; | ||
246 | |||
247 | #ifdef i1480u_FLOW_CONTROL | ||
248 | /* Notification endpoint setup (submitted when we open the device) */ | ||
249 | i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
250 | if (i1480u->notif_urb == NULL) { | ||
251 | dev_err(&iface->dev, "Unable to allocate notification URB\n"); | ||
252 | result = -ENOMEM; | ||
253 | goto error_urb_alloc; | ||
254 | } | ||
255 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
256 | usb_fill_int_urb(i1480u->notif_urb, usb_dev, | ||
257 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
258 | i1480u->notif_buffer, sizeof(i1480u->notif_buffer), | ||
259 | i1480u_notif_cb, i1480u, epd->bInterval); | ||
260 | |||
261 | #endif | ||
262 | |||
263 | i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; | ||
264 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
265 | i1480u->tx_inflight.restart_ts = jiffies; | ||
266 | usb_set_intfdata(iface, i1480u); | ||
267 | return result; | ||
268 | |||
269 | #ifdef i1480u_FLOW_CONTROL | ||
270 | error_urb_alloc: | ||
271 | #endif | ||
272 | wlp_remove(wlp); | ||
273 | error_wlp_setup: | ||
274 | uwb_rc_put(rc); | ||
275 | out: | ||
276 | usb_put_dev(i1480u->usb_dev); | ||
277 | return result; | ||
278 | } | ||
279 | |||
280 | static void i1480u_rm(struct i1480u *i1480u) | ||
281 | { | ||
282 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
283 | usb_set_intfdata(i1480u->usb_iface, NULL); | ||
284 | #ifdef i1480u_FLOW_CONTROL | ||
285 | usb_kill_urb(i1480u->notif_urb); | ||
286 | usb_free_urb(i1480u->notif_urb); | ||
287 | #endif | ||
288 | wlp_remove(&i1480u->wlp); | ||
289 | uwb_rc_put(rc); | ||
290 | usb_put_dev(i1480u->usb_dev); | ||
291 | } | ||
292 | |||
293 | /** Just setup @net_dev's i1480u private data */ | ||
294 | static void i1480u_netdev_setup(struct net_device *net_dev) | ||
295 | { | ||
296 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
297 | /* Initialize @i1480u */ | ||
298 | memset(i1480u, 0, sizeof(*i1480u)); | ||
299 | i1480u_init(i1480u); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Probe a i1480u interface and register it | ||
304 | * | ||
305 | * @iface: USB interface to link to | ||
306 | * @id: USB class/subclass/protocol id | ||
307 | * @returns: 0 if ok, < 0 errno code on error. | ||
308 | * | ||
309 | * Does basic housekeeping stuff and then allocs a netdev with space | ||
310 | * for the i1480u data. Initializes, registers in i1480u, registers in | ||
311 | * netdev, ready to go. | ||
312 | */ | ||
313 | static int i1480u_probe(struct usb_interface *iface, | ||
314 | const struct usb_device_id *id) | ||
315 | { | ||
316 | int result; | ||
317 | struct net_device *net_dev; | ||
318 | struct device *dev = &iface->dev; | ||
319 | struct i1480u *i1480u; | ||
320 | |||
321 | /* Allocate instance [calls i1480u_netdev_setup() on it] */ | ||
322 | result = -ENOMEM; | ||
323 | net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); | ||
324 | if (net_dev == NULL) { | ||
325 | dev_err(dev, "no memory for network device instance\n"); | ||
326 | goto error_alloc_netdev; | ||
327 | } | ||
328 | SET_NETDEV_DEV(net_dev, dev); | ||
329 | i1480u = netdev_priv(net_dev); | ||
330 | i1480u->net_dev = net_dev; | ||
331 | result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ | ||
332 | if (result < 0) { | ||
333 | dev_err(dev, "cannot add i1480u device: %d\n", result); | ||
334 | goto error_i1480u_add; | ||
335 | } | ||
336 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | ||
337 | if (result < 0) { | ||
338 | dev_err(dev, "cannot register network device: %d\n", result); | ||
339 | goto error_register_netdev; | ||
340 | } | ||
341 | i1480u_sysfs_setup(i1480u); | ||
342 | if (result < 0) | ||
343 | goto error_sysfs_init; | ||
344 | return 0; | ||
345 | |||
346 | error_sysfs_init: | ||
347 | unregister_netdev(net_dev); | ||
348 | error_register_netdev: | ||
349 | i1480u_rm(i1480u); | ||
350 | error_i1480u_add: | ||
351 | free_netdev(net_dev); | ||
352 | error_alloc_netdev: | ||
353 | return result; | ||
354 | } | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Disconect a i1480u from the system. | ||
359 | * | ||
360 | * i1480u_stop() has been called before, so al the rx and tx contexts | ||
361 | * have been taken down already. Make sure the queue is stopped, | ||
362 | * unregister netdev and i1480u, free and kill. | ||
363 | */ | ||
364 | static void i1480u_disconnect(struct usb_interface *iface) | ||
365 | { | ||
366 | struct i1480u *i1480u; | ||
367 | struct net_device *net_dev; | ||
368 | |||
369 | i1480u = usb_get_intfdata(iface); | ||
370 | net_dev = i1480u->net_dev; | ||
371 | netif_stop_queue(net_dev); | ||
372 | #ifdef i1480u_FLOW_CONTROL | ||
373 | usb_kill_urb(i1480u->notif_urb); | ||
374 | #endif | ||
375 | i1480u_sysfs_release(i1480u); | ||
376 | unregister_netdev(net_dev); | ||
377 | i1480u_rm(i1480u); | ||
378 | free_netdev(net_dev); | ||
379 | } | ||
380 | |||
381 | static struct usb_device_id i1480u_id_table[] = { | ||
382 | { | ||
383 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | ||
384 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | ||
385 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
386 | .idVendor = 0x8086, | ||
387 | .idProduct = 0x0c3b, | ||
388 | .bDeviceClass = 0xef, | ||
389 | .bDeviceSubClass = 0x02, | ||
390 | .bDeviceProtocol = 0x02, | ||
391 | .bInterfaceClass = 0xff, | ||
392 | .bInterfaceSubClass = 0xff, | ||
393 | .bInterfaceProtocol = 0xff, | ||
394 | }, | ||
395 | {}, | ||
396 | }; | ||
397 | MODULE_DEVICE_TABLE(usb, i1480u_id_table); | ||
398 | |||
399 | static struct usb_driver i1480u_driver = { | ||
400 | .name = KBUILD_MODNAME, | ||
401 | .probe = i1480u_probe, | ||
402 | .disconnect = i1480u_disconnect, | ||
403 | .id_table = i1480u_id_table, | ||
404 | }; | ||
405 | |||
406 | static int __init i1480u_driver_init(void) | ||
407 | { | ||
408 | return usb_register(&i1480u_driver); | ||
409 | } | ||
410 | module_init(i1480u_driver_init); | ||
411 | |||
412 | |||
413 | static void __exit i1480u_driver_exit(void) | ||
414 | { | ||
415 | usb_deregister(&i1480u_driver); | ||
416 | } | ||
417 | module_exit(i1480u_driver_exit); | ||
418 | |||
419 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
420 | MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB"); | ||
421 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c new file mode 100644 index 000000000000..8802ac43d872 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/netdev.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * Implementation of the netdevice linkage (except tx and rx related stuff). | ||
26 | * | ||
27 | * ROADMAP: | ||
28 | * | ||
29 | * ENTRY POINTS (Net device): | ||
30 | * | ||
31 | * i1480u_open(): Called when we ifconfig up the interface; | ||
32 | * associates to a UWB host controller, reserves | ||
33 | * bandwidth (MAS), sets up RX USB URB and starts | ||
34 | * the queue. | ||
35 | * | ||
36 | * i1480u_stop(): Called when we ifconfig down a interface; | ||
37 | * reverses _open(). | ||
38 | * | ||
39 | * i1480u_set_config(): | ||
40 | */ | ||
41 | |||
42 | #include <linux/if_arp.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <linux/uwb/debug.h> | ||
45 | #include "i1480u-wlp.h" | ||
46 | |||
47 | struct i1480u_cmd_set_ip_mas { | ||
48 | struct uwb_rccb rccb; | ||
49 | struct uwb_dev_addr addr; | ||
50 | u8 stream; | ||
51 | u8 owner; | ||
52 | u8 type; /* enum uwb_drp_type */ | ||
53 | u8 baMAS[32]; | ||
54 | } __attribute__((packed)); | ||
55 | |||
56 | |||
57 | static | ||
58 | int i1480u_set_ip_mas( | ||
59 | struct uwb_rc *rc, | ||
60 | const struct uwb_dev_addr *dstaddr, | ||
61 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
62 | { | ||
63 | |||
64 | int result; | ||
65 | struct i1480u_cmd_set_ip_mas *cmd; | ||
66 | struct uwb_rc_evt_confirm reply; | ||
67 | |||
68 | result = -ENOMEM; | ||
69 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
70 | if (cmd == NULL) | ||
71 | goto error_kzalloc; | ||
72 | cmd->rccb.bCommandType = 0xfd; | ||
73 | cmd->rccb.wCommand = cpu_to_le16(0x000e); | ||
74 | cmd->addr = *dstaddr; | ||
75 | cmd->stream = stream; | ||
76 | cmd->owner = owner; | ||
77 | cmd->type = type; | ||
78 | if (mas == NULL) | ||
79 | memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS)); | ||
80 | else | ||
81 | memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS)); | ||
82 | reply.rceb.bEventType = 0xfd; | ||
83 | reply.rceb.wEvent = cpu_to_le16(0x000e); | ||
84 | result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd), | ||
85 | &reply.rceb, sizeof(reply)); | ||
86 | if (result < 0) | ||
87 | goto error_cmd; | ||
88 | if (reply.bResultCode != UWB_RC_RES_FAIL) { | ||
89 | dev_err(&rc->uwb_dev.dev, | ||
90 | "SET-IP-MAS: command execution failed: %d\n", | ||
91 | reply.bResultCode); | ||
92 | result = -EIO; | ||
93 | } | ||
94 | error_cmd: | ||
95 | kfree(cmd); | ||
96 | error_kzalloc: | ||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Inform a WLP interface of a MAS reservation | ||
102 | * | ||
103 | * @rc is assumed refcnted. | ||
104 | */ | ||
105 | /* FIXME: detect if remote device is WLP capable? */ | ||
106 | static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc, | ||
107 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
108 | { | ||
109 | int result = 0; | ||
110 | struct device *dev = &rc->uwb_dev.dev; | ||
111 | |||
112 | result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner, | ||
113 | type, mas); | ||
114 | if (result < 0) { | ||
115 | char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE]; | ||
116 | uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf), | ||
117 | &rc->uwb_dev.dev_addr); | ||
118 | uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf), | ||
119 | &uwb_dev->dev_addr); | ||
120 | dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n", | ||
121 | rcaddrbuf, devaddrbuf, result); | ||
122 | } | ||
123 | return result; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Called by bandwidth allocator when change occurs in reservation. | ||
128 | * | ||
129 | * @rsv: The reservation that is being established, modified, or | ||
130 | * terminated. | ||
131 | * | ||
132 | * When a reservation is established, modified, or terminated the upper layer | ||
133 | * (WLP here) needs set/update the currently available Media Access Slots | ||
134 | * that can be use for IP traffic. | ||
135 | * | ||
136 | * Our action taken during failure depends on how the reservation is being | ||
137 | * changed: | ||
138 | * - if reservation is being established we do nothing if we cannot set the | ||
139 | * new MAS to be used | ||
140 | * - if reservation is being terminated we revert back to PCA whether the | ||
141 | * SET IP MAS command succeeds or not. | ||
142 | */ | ||
143 | void i1480u_bw_alloc_cb(struct uwb_rsv *rsv) | ||
144 | { | ||
145 | int result = 0; | ||
146 | struct i1480u *i1480u = rsv->pal_priv; | ||
147 | struct device *dev = &i1480u->usb_iface->dev; | ||
148 | struct uwb_dev *target_dev = rsv->target.dev; | ||
149 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
150 | u8 stream = rsv->stream; | ||
151 | int type = rsv->type; | ||
152 | int is_owner = rsv->owner == &rc->uwb_dev; | ||
153 | unsigned long *bmp = rsv->mas.bm; | ||
154 | |||
155 | dev_err(dev, "WLP callback called - sending set ip mas\n"); | ||
156 | /*user cannot change options while setting configuration*/ | ||
157 | mutex_lock(&i1480u->options.mutex); | ||
158 | switch (rsv->state) { | ||
159 | case UWB_RSV_STATE_T_ACCEPTED: | ||
160 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
161 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
162 | type, bmp); | ||
163 | if (result < 0) { | ||
164 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
165 | goto out; | ||
166 | } | ||
167 | if (is_owner) { | ||
168 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
169 | WLP_DRP | stream); | ||
170 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0); | ||
171 | } | ||
172 | break; | ||
173 | case UWB_RSV_STATE_NONE: | ||
174 | /* revert back to PCA */ | ||
175 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
176 | type, bmp); | ||
177 | if (result < 0) | ||
178 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
179 | /* Revert to PCA even though SET IP MAS failed. */ | ||
180 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
181 | i1480u->options.pca_base_priority); | ||
182 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1); | ||
183 | break; | ||
184 | default: | ||
185 | dev_err(dev, "unexpected WLP reservation state: %s (%d).\n", | ||
186 | uwb_rsv_state_str(rsv->state), rsv->state); | ||
187 | break; | ||
188 | } | ||
189 | out: | ||
190 | mutex_unlock(&i1480u->options.mutex); | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * | ||
196 | * Called on 'ifconfig up' | ||
197 | */ | ||
198 | int i1480u_open(struct net_device *net_dev) | ||
199 | { | ||
200 | int result; | ||
201 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
202 | struct wlp *wlp = &i1480u->wlp; | ||
203 | struct uwb_rc *rc; | ||
204 | struct device *dev = &i1480u->usb_iface->dev; | ||
205 | |||
206 | rc = wlp->rc; | ||
207 | result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */ | ||
208 | if (result < 0) | ||
209 | goto error_rx_setup; | ||
210 | netif_wake_queue(net_dev); | ||
211 | #ifdef i1480u_FLOW_CONTROL | ||
212 | result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);; | ||
213 | if (result < 0) { | ||
214 | dev_err(dev, "Can't submit notification URB: %d\n", result); | ||
215 | goto error_notif_urb_submit; | ||
216 | } | ||
217 | #endif | ||
218 | i1480u->uwb_notifs_handler.cb = i1480u_uwb_notifs_cb; | ||
219 | i1480u->uwb_notifs_handler.data = i1480u; | ||
220 | if (uwb_bg_joined(rc)) | ||
221 | netif_carrier_on(net_dev); | ||
222 | else | ||
223 | netif_carrier_off(net_dev); | ||
224 | uwb_notifs_register(rc, &i1480u->uwb_notifs_handler); | ||
225 | /* Interface is up with an address, now we can create WSS */ | ||
226 | result = wlp_wss_setup(net_dev, &wlp->wss); | ||
227 | if (result < 0) { | ||
228 | dev_err(dev, "Can't create WSS: %d. \n", result); | ||
229 | goto error_notif_deregister; | ||
230 | } | ||
231 | return 0; | ||
232 | error_notif_deregister: | ||
233 | uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); | ||
234 | #ifdef i1480u_FLOW_CONTROL | ||
235 | error_notif_urb_submit: | ||
236 | #endif | ||
237 | netif_stop_queue(net_dev); | ||
238 | i1480u_rx_release(i1480u); | ||
239 | error_rx_setup: | ||
240 | return result; | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Called on 'ifconfig down' | ||
246 | */ | ||
247 | int i1480u_stop(struct net_device *net_dev) | ||
248 | { | ||
249 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
250 | struct wlp *wlp = &i1480u->wlp; | ||
251 | struct uwb_rc *rc = wlp->rc; | ||
252 | |||
253 | BUG_ON(wlp->rc == NULL); | ||
254 | wlp_wss_remove(&wlp->wss); | ||
255 | uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); | ||
256 | netif_carrier_off(net_dev); | ||
257 | #ifdef i1480u_FLOW_CONTROL | ||
258 | usb_kill_urb(i1480u->notif_urb); | ||
259 | #endif | ||
260 | netif_stop_queue(net_dev); | ||
261 | i1480u_rx_release(i1480u); | ||
262 | i1480u_tx_release(i1480u); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | |||
267 | /** Report statistics */ | ||
268 | struct net_device_stats *i1480u_get_stats(struct net_device *net_dev) | ||
269 | { | ||
270 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
271 | return &i1480u->stats; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * | ||
277 | * Change the interface config--we probably don't have to do anything. | ||
278 | */ | ||
279 | int i1480u_set_config(struct net_device *net_dev, struct ifmap *map) | ||
280 | { | ||
281 | int result; | ||
282 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
283 | BUG_ON(i1480u->wlp.rc == NULL); | ||
284 | result = 0; | ||
285 | return result; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * Change the MTU of the interface | ||
290 | */ | ||
291 | int i1480u_change_mtu(struct net_device *net_dev, int mtu) | ||
292 | { | ||
293 | static union { | ||
294 | struct wlp_tx_hdr tx; | ||
295 | struct wlp_rx_hdr rx; | ||
296 | } i1480u_all_hdrs; | ||
297 | |||
298 | if (mtu < ETH_HLEN) /* We encap eth frames */ | ||
299 | return -ERANGE; | ||
300 | if (mtu > 4000 - sizeof(i1480u_all_hdrs)) | ||
301 | return -ERANGE; | ||
302 | net_dev->mtu = mtu; | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Callback function to handle events from UWB | ||
309 | * When we see other devices we know the carrier is ok, | ||
310 | * if we are the only device in the beacon group we set the carrier | ||
311 | * state to off. | ||
312 | * */ | ||
313 | void i1480u_uwb_notifs_cb(void *data, struct uwb_dev *uwb_dev, | ||
314 | enum uwb_notifs event) | ||
315 | { | ||
316 | struct i1480u *i1480u = data; | ||
317 | struct net_device *net_dev = i1480u->net_dev; | ||
318 | struct device *dev = &i1480u->usb_iface->dev; | ||
319 | switch (event) { | ||
320 | case UWB_NOTIF_BG_JOIN: | ||
321 | netif_carrier_on(net_dev); | ||
322 | dev_info(dev, "Link is up\n"); | ||
323 | break; | ||
324 | case UWB_NOTIF_BG_LEAVE: | ||
325 | netif_carrier_off(net_dev); | ||
326 | dev_info(dev, "Link is down\n"); | ||
327 | break; | ||
328 | default: | ||
329 | dev_err(dev, "don't know how to handle event %d from uwb\n", | ||
330 | event); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * Stop the network queue | ||
336 | * | ||
337 | * Enable WLP substack to stop network queue. We also set the flow control | ||
338 | * threshold at this time to prevent the flow control from restarting the | ||
339 | * queue. | ||
340 | * | ||
341 | * we are loosing the current threshold value here ... FIXME? | ||
342 | */ | ||
343 | void i1480u_stop_queue(struct wlp *wlp) | ||
344 | { | ||
345 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
346 | struct net_device *net_dev = i1480u->net_dev; | ||
347 | i1480u->tx_inflight.threshold = 0; | ||
348 | netif_stop_queue(net_dev); | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * Start the network queue | ||
353 | * | ||
354 | * Enable WLP substack to start network queue. Also re-enable the flow | ||
355 | * control to manage the queue again. | ||
356 | * | ||
357 | * We re-enable the flow control by storing the default threshold in the | ||
358 | * flow control threshold. This means that if the user modified the | ||
359 | * threshold before the queue was stopped and restarted that information | ||
360 | * will be lost. FIXME? | ||
361 | */ | ||
362 | void i1480u_start_queue(struct wlp *wlp) | ||
363 | { | ||
364 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
365 | struct net_device *net_dev = i1480u->net_dev; | ||
366 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
367 | netif_start_queue(net_dev); | ||
368 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c new file mode 100644 index 000000000000..9fc035354a76 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/rx.c | |||
@@ -0,0 +1,486 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * i1480u's RX handling is simple. i1480u will send the received | ||
24 | * network packets broken up in fragments; 1 to N fragments make a | ||
25 | * packet, we assemble them together and deliver the packet with netif_rx(). | ||
26 | * | ||
27 | * Beacuse each USB transfer is a *single* fragment (except when the | ||
28 | * transfer contains a first fragment), each URB called thus | ||
29 | * back contains one or two fragments. So we queue N URBs, each with its own | ||
30 | * fragment buffer. When a URB is done, we process it (adding to the | ||
31 | * current skb from the fragment buffer until complete). Once | ||
32 | * processed, we requeue the URB. There is always a bunch of URBs | ||
33 | * ready to take data, so the intergap should be minimal. | ||
34 | * | ||
35 | * An URB's transfer buffer is the data field of a socket buffer. This | ||
36 | * reduces copying as data can be passed directly to network layer. If a | ||
37 | * complete packet or 1st fragment is received the URB's transfer buffer is | ||
38 | * taken away from it and used to send data to the network layer. In this | ||
39 | * case a new transfer buffer is allocated to the URB before being requeued. | ||
40 | * If a "NEXT" or "LAST" fragment is received, the fragment contents is | ||
41 | * appended to the RX packet under construction and the transfer buffer | ||
42 | * is reused. To be able to use this buffer to assemble complete packets | ||
43 | * we set each buffer's size to that of the MAX ethernet packet that can | ||
44 | * be received. There is thus room for improvement in memory usage. | ||
45 | * | ||
46 | * When the max tx fragment size increases, we should be able to read | ||
47 | * data into the skbs directly with very simple code. | ||
48 | * | ||
49 | * ROADMAP: | ||
50 | * | ||
51 | * ENTRY POINTS: | ||
52 | * | ||
53 | * i1480u_rx_setup(): setup RX context [from i1480u_open()] | ||
54 | * | ||
55 | * i1480u_rx_release(): release RX context [from i1480u_stop()] | ||
56 | * | ||
57 | * i1480u_rx_cb(): called when the RX USB URB receives a | ||
58 | * packet. It removes the header and pushes it up | ||
59 | * the Linux netdev stack with netif_rx(). | ||
60 | * | ||
61 | * i1480u_rx_buffer() | ||
62 | * i1480u_drop() and i1480u_fix() | ||
63 | * i1480u_skb_deliver | ||
64 | * | ||
65 | */ | ||
66 | |||
67 | #include <linux/netdevice.h> | ||
68 | #include <linux/etherdevice.h> | ||
69 | #include "i1480u-wlp.h" | ||
70 | |||
71 | #define D_LOCAL 0 | ||
72 | #include <linux/uwb/debug.h> | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Setup the RX context | ||
77 | * | ||
78 | * Each URB is provided with a transfer_buffer that is the data field | ||
79 | * of a new socket buffer. | ||
80 | */ | ||
81 | int i1480u_rx_setup(struct i1480u *i1480u) | ||
82 | { | ||
83 | int result, cnt; | ||
84 | struct device *dev = &i1480u->usb_iface->dev; | ||
85 | struct net_device *net_dev = i1480u->net_dev; | ||
86 | struct usb_endpoint_descriptor *epd; | ||
87 | struct sk_buff *skb; | ||
88 | |||
89 | /* Alloc RX stuff */ | ||
90 | i1480u->rx_skb = NULL; /* not in process of receiving packet */ | ||
91 | result = -ENOMEM; | ||
92 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc; | ||
93 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
94 | struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt]; | ||
95 | rx_buf->i1480u = i1480u; | ||
96 | skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
97 | if (!skb) { | ||
98 | dev_err(dev, | ||
99 | "RX: cannot allocate RX buffer %d\n", cnt); | ||
100 | result = -ENOMEM; | ||
101 | goto error; | ||
102 | } | ||
103 | skb->dev = net_dev; | ||
104 | skb->ip_summed = CHECKSUM_NONE; | ||
105 | skb_reserve(skb, 2); | ||
106 | rx_buf->data = skb; | ||
107 | rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
108 | if (unlikely(rx_buf->urb == NULL)) { | ||
109 | dev_err(dev, "RX: cannot allocate URB %d\n", cnt); | ||
110 | result = -ENOMEM; | ||
111 | goto error; | ||
112 | } | ||
113 | usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev, | ||
114 | usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress), | ||
115 | rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2, | ||
116 | i1480u_rx_cb, rx_buf); | ||
117 | result = usb_submit_urb(rx_buf->urb, GFP_NOIO); | ||
118 | if (unlikely(result < 0)) { | ||
119 | dev_err(dev, "RX: cannot submit URB %d: %d\n", | ||
120 | cnt, result); | ||
121 | goto error; | ||
122 | } | ||
123 | } | ||
124 | return 0; | ||
125 | |||
126 | error: | ||
127 | i1480u_rx_release(i1480u); | ||
128 | return result; | ||
129 | } | ||
130 | |||
131 | |||
132 | /** Release resources associated to the rx context */ | ||
133 | void i1480u_rx_release(struct i1480u *i1480u) | ||
134 | { | ||
135 | int cnt; | ||
136 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
137 | if (i1480u->rx_buf[cnt].data) | ||
138 | dev_kfree_skb(i1480u->rx_buf[cnt].data); | ||
139 | if (i1480u->rx_buf[cnt].urb) { | ||
140 | usb_kill_urb(i1480u->rx_buf[cnt].urb); | ||
141 | usb_free_urb(i1480u->rx_buf[cnt].urb); | ||
142 | } | ||
143 | } | ||
144 | if (i1480u->rx_skb != NULL) | ||
145 | dev_kfree_skb(i1480u->rx_skb); | ||
146 | } | ||
147 | |||
148 | static | ||
149 | void i1480u_rx_unlink_urbs(struct i1480u *i1480u) | ||
150 | { | ||
151 | int cnt; | ||
152 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
153 | if (i1480u->rx_buf[cnt].urb) | ||
154 | usb_unlink_urb(i1480u->rx_buf[cnt].urb); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /** Fix an out-of-sequence packet */ | ||
159 | #define i1480u_fix(i1480u, msg...) \ | ||
160 | do { \ | ||
161 | if (printk_ratelimit()) \ | ||
162 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
163 | dev_kfree_skb_irq(i1480u->rx_skb); \ | ||
164 | i1480u->rx_skb = NULL; \ | ||
165 | i1480u->rx_untd_pkt_size = 0; \ | ||
166 | } while (0) | ||
167 | |||
168 | |||
169 | /** Drop an out-of-sequence packet */ | ||
170 | #define i1480u_drop(i1480u, msg...) \ | ||
171 | do { \ | ||
172 | if (printk_ratelimit()) \ | ||
173 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
174 | i1480u->stats.rx_dropped++; \ | ||
175 | } while (0) | ||
176 | |||
177 | |||
178 | |||
179 | |||
180 | /** Finalizes setting up the SKB and delivers it | ||
181 | * | ||
182 | * We first pass the incoming frame to WLP substack for verification. It | ||
183 | * may also be a WLP association frame in which case WLP will take over the | ||
184 | * processing. If WLP does not take it over it will still verify it, if the | ||
185 | * frame is invalid the skb will be freed by WLP and we will not continue | ||
186 | * parsing. | ||
187 | * */ | ||
188 | static | ||
189 | void i1480u_skb_deliver(struct i1480u *i1480u) | ||
190 | { | ||
191 | int should_parse; | ||
192 | struct net_device *net_dev = i1480u->net_dev; | ||
193 | struct device *dev = &i1480u->usb_iface->dev; | ||
194 | |||
195 | d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n", | ||
196 | i1480u->rx_skb, i1480u->rx_skb->len); | ||
197 | d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len); | ||
198 | should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb, | ||
199 | &i1480u->rx_srcaddr); | ||
200 | if (!should_parse) | ||
201 | goto out; | ||
202 | i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); | ||
203 | d_printf(5, dev, "RX delivered skb(%p), %u bytes\n", | ||
204 | i1480u->rx_skb, i1480u->rx_skb->len); | ||
205 | d_dump(7, dev, i1480u->rx_skb->data, | ||
206 | i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len); | ||
207 | i1480u->stats.rx_packets++; | ||
208 | i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size; | ||
209 | net_dev->last_rx = jiffies; | ||
210 | /* FIXME: flow control: check netif_rx() retval */ | ||
211 | |||
212 | netif_rx(i1480u->rx_skb); /* deliver */ | ||
213 | out: | ||
214 | i1480u->rx_skb = NULL; | ||
215 | i1480u->rx_untd_pkt_size = 0; | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Process a buffer of data received from the USB RX endpoint | ||
221 | * | ||
222 | * First fragment arrives with next or last fragment. All other fragments | ||
223 | * arrive alone. | ||
224 | * | ||
225 | * /me hates long functions. | ||
226 | */ | ||
227 | static | ||
228 | void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf) | ||
229 | { | ||
230 | unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */ | ||
231 | size_t untd_hdr_size, untd_frg_size; | ||
232 | size_t i1480u_hdr_size; | ||
233 | struct wlp_rx_hdr *i1480u_hdr = NULL; | ||
234 | |||
235 | struct i1480u *i1480u = rx_buf->i1480u; | ||
236 | struct sk_buff *skb = rx_buf->data; | ||
237 | int size_left = rx_buf->urb->actual_length; | ||
238 | void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */ | ||
239 | struct untd_hdr *untd_hdr; | ||
240 | |||
241 | struct net_device *net_dev = i1480u->net_dev; | ||
242 | struct device *dev = &i1480u->usb_iface->dev; | ||
243 | struct sk_buff *new_skb; | ||
244 | |||
245 | #if 0 | ||
246 | dev_fnstart(dev, | ||
247 | "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left); | ||
248 | dev_err(dev, "RX packet, %zu bytes\n", size_left); | ||
249 | dump_bytes(dev, ptr, size_left); | ||
250 | #endif | ||
251 | i1480u_hdr_size = sizeof(struct wlp_rx_hdr); | ||
252 | |||
253 | while (size_left > 0) { | ||
254 | if (pkt_completed) { | ||
255 | i1480u_drop(i1480u, "RX: fragment follows completed" | ||
256 | "packet in same buffer. Dropping\n"); | ||
257 | break; | ||
258 | } | ||
259 | untd_hdr = ptr; | ||
260 | if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */ | ||
261 | i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n"); | ||
262 | goto out; | ||
263 | } | ||
264 | if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */ | ||
265 | i1480u_drop(i1480u, "RX: TX bit set! Dropping\n"); | ||
266 | goto out; | ||
267 | } | ||
268 | switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */ | ||
269 | case i1480u_PKT_FRAG_1ST: { | ||
270 | struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr; | ||
271 | dev_dbg(dev, "1st fragment\n"); | ||
272 | untd_hdr_size = sizeof(struct untd_hdr_1st); | ||
273 | if (i1480u->rx_skb != NULL) | ||
274 | i1480u_fix(i1480u, "RX: 1st fragment out of " | ||
275 | "sequence! Fixing\n"); | ||
276 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
277 | i1480u_drop(i1480u, "RX: short 1st fragment! " | ||
278 | "Dropping\n"); | ||
279 | goto out; | ||
280 | } | ||
281 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len) | ||
282 | - i1480u_hdr_size; | ||
283 | untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len); | ||
284 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
285 | i1480u_drop(i1480u, | ||
286 | "RX: short payload! Dropping\n"); | ||
287 | goto out; | ||
288 | } | ||
289 | i1480u->rx_skb = skb; | ||
290 | i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size; | ||
291 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
292 | skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size); | ||
293 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
294 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
295 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
296 | rx_buf->data = NULL; /* need to create new buffer */ | ||
297 | break; | ||
298 | } | ||
299 | case i1480u_PKT_FRAG_NXT: { | ||
300 | dev_dbg(dev, "nxt fragment\n"); | ||
301 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
302 | if (i1480u->rx_skb == NULL) { | ||
303 | i1480u_drop(i1480u, "RX: next fragment out of " | ||
304 | "sequence! Dropping\n"); | ||
305 | goto out; | ||
306 | } | ||
307 | if (size_left < untd_hdr_size) { | ||
308 | i1480u_drop(i1480u, "RX: short NXT fragment! " | ||
309 | "Dropping\n"); | ||
310 | goto out; | ||
311 | } | ||
312 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
313 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
314 | i1480u_drop(i1480u, | ||
315 | "RX: short payload! Dropping\n"); | ||
316 | goto out; | ||
317 | } | ||
318 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
319 | ptr + untd_hdr_size, untd_frg_size); | ||
320 | break; | ||
321 | } | ||
322 | case i1480u_PKT_FRAG_LST: { | ||
323 | dev_dbg(dev, "Lst fragment\n"); | ||
324 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
325 | if (i1480u->rx_skb == NULL) { | ||
326 | i1480u_drop(i1480u, "RX: last fragment out of " | ||
327 | "sequence! Dropping\n"); | ||
328 | goto out; | ||
329 | } | ||
330 | if (size_left < untd_hdr_size) { | ||
331 | i1480u_drop(i1480u, "RX: short LST fragment! " | ||
332 | "Dropping\n"); | ||
333 | goto out; | ||
334 | } | ||
335 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
336 | if (size_left < untd_frg_size + untd_hdr_size) { | ||
337 | i1480u_drop(i1480u, | ||
338 | "RX: short payload! Dropping\n"); | ||
339 | goto out; | ||
340 | } | ||
341 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
342 | ptr + untd_hdr_size, untd_frg_size); | ||
343 | pkt_completed = 1; | ||
344 | break; | ||
345 | } | ||
346 | case i1480u_PKT_FRAG_CMP: { | ||
347 | dev_dbg(dev, "cmp fragment\n"); | ||
348 | untd_hdr_size = sizeof(struct untd_hdr_cmp); | ||
349 | if (i1480u->rx_skb != NULL) | ||
350 | i1480u_fix(i1480u, "RX: fix out-of-sequence CMP" | ||
351 | " fragment!\n"); | ||
352 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
353 | i1480u_drop(i1480u, "RX: short CMP fragment! " | ||
354 | "Dropping\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len); | ||
358 | untd_frg_size = i1480u->rx_untd_pkt_size; | ||
359 | if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) { | ||
360 | i1480u_drop(i1480u, | ||
361 | "RX: short payload! Dropping\n"); | ||
362 | goto out; | ||
363 | } | ||
364 | i1480u->rx_skb = skb; | ||
365 | i1480u_hdr = (void *) untd_hdr + untd_hdr_size; | ||
366 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
367 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
368 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
369 | skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size); | ||
370 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
371 | rx_buf->data = NULL; /* for hand off skb to network stack */ | ||
372 | pkt_completed = 1; | ||
373 | i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */ | ||
374 | break; | ||
375 | } | ||
376 | default: | ||
377 | i1480u_drop(i1480u, "RX: unknown packet type %u! " | ||
378 | "Dropping\n", untd_hdr_type(untd_hdr)); | ||
379 | goto out; | ||
380 | } | ||
381 | size_left -= untd_hdr_size + untd_frg_size; | ||
382 | if (size_left > 0) | ||
383 | ptr += untd_hdr_size + untd_frg_size; | ||
384 | } | ||
385 | if (pkt_completed) | ||
386 | i1480u_skb_deliver(i1480u); | ||
387 | out: | ||
388 | /* recreate needed RX buffers*/ | ||
389 | if (rx_buf->data == NULL) { | ||
390 | /* buffer is being used to receive packet, create new */ | ||
391 | new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
392 | if (!new_skb) { | ||
393 | if (printk_ratelimit()) | ||
394 | dev_err(dev, | ||
395 | "RX: cannot allocate RX buffer\n"); | ||
396 | } else { | ||
397 | new_skb->dev = net_dev; | ||
398 | new_skb->ip_summed = CHECKSUM_NONE; | ||
399 | skb_reserve(new_skb, 2); | ||
400 | rx_buf->data = new_skb; | ||
401 | } | ||
402 | } | ||
403 | return; | ||
404 | } | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Called when an RX URB has finished receiving or has found some kind | ||
409 | * of error condition. | ||
410 | * | ||
411 | * LIMITATIONS: | ||
412 | * | ||
413 | * - We read USB-transfers, each transfer contains a SINGLE fragment | ||
414 | * (can contain a complete packet, or a 1st, next, or last fragment | ||
415 | * of a packet). | ||
416 | * Looks like a transfer can contain more than one fragment (07/18/06) | ||
417 | * | ||
418 | * - Each transfer buffer is the size of the maximum packet size (minus | ||
419 | * headroom), i1480u_MAX_PKT_SIZE - 2 | ||
420 | * | ||
421 | * - We always read the full USB-transfer, no partials. | ||
422 | * | ||
423 | * - Each transfer is read directly into a skb. This skb will be used to | ||
424 | * send data to the upper layers if it is the first fragment or a complete | ||
425 | * packet. In the other cases the data will be copied from the skb to | ||
426 | * another skb that is being prepared for the upper layers from a prev | ||
427 | * first fragment. | ||
428 | * | ||
429 | * It is simply too much of a pain. Gosh, there should be a unified | ||
430 | * SG infrastructure for *everything* [so that I could declare a SG | ||
431 | * buffer, pass it to USB for receiving, append some space to it if | ||
432 | * I wish, receive more until I have the whole chunk, adapt | ||
433 | * pointers on each fragment to remove hardware headers and then | ||
434 | * attach that to an skbuff and netif_rx()]. | ||
435 | */ | ||
436 | void i1480u_rx_cb(struct urb *urb) | ||
437 | { | ||
438 | int result; | ||
439 | int do_parse_buffer = 1; | ||
440 | struct i1480u_rx_buf *rx_buf = urb->context; | ||
441 | struct i1480u *i1480u = rx_buf->i1480u; | ||
442 | struct device *dev = &i1480u->usb_iface->dev; | ||
443 | unsigned long flags; | ||
444 | u8 rx_buf_idx = rx_buf - i1480u->rx_buf; | ||
445 | |||
446 | switch (urb->status) { | ||
447 | case 0: | ||
448 | break; | ||
449 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
450 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
451 | case -ESHUTDOWN: /* going away! */ | ||
452 | dev_err(dev, "RX URB[%u]: goind down %d\n", | ||
453 | rx_buf_idx, urb->status); | ||
454 | goto error; | ||
455 | default: | ||
456 | dev_err(dev, "RX URB[%u]: unknown status %d\n", | ||
457 | rx_buf_idx, urb->status); | ||
458 | if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS, | ||
459 | EDC_ERROR_TIMEFRAME)) { | ||
460 | dev_err(dev, "RX: max acceptable errors exceeded," | ||
461 | " resetting device.\n"); | ||
462 | i1480u_rx_unlink_urbs(i1480u); | ||
463 | wlp_reset_all(&i1480u->wlp); | ||
464 | goto error; | ||
465 | } | ||
466 | do_parse_buffer = 0; | ||
467 | break; | ||
468 | } | ||
469 | spin_lock_irqsave(&i1480u->lock, flags); | ||
470 | /* chew the data fragments, extract network packets */ | ||
471 | if (do_parse_buffer) { | ||
472 | i1480u_rx_buffer(rx_buf); | ||
473 | if (rx_buf->data) { | ||
474 | rx_buf->urb->transfer_buffer = rx_buf->data->data; | ||
475 | result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC); | ||
476 | if (result < 0) { | ||
477 | dev_err(dev, "RX URB[%u]: cannot submit %d\n", | ||
478 | rx_buf_idx, result); | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
483 | error: | ||
484 | return; | ||
485 | } | ||
486 | |||
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c new file mode 100644 index 000000000000..a1d8ca6ac935 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/sysfs.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Sysfs interfaces | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/uwb/debug.h> | ||
29 | #include <linux/device.h> | ||
30 | #include "i1480u-wlp.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * | ||
35 | * @dev: Class device from the net_device; assumed refcnted. | ||
36 | * | ||
37 | * Yes, I don't lock--we assume it is refcounted and I am getting a | ||
38 | * single byte value that is kind of atomic to read. | ||
39 | */ | ||
40 | ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf) | ||
41 | { | ||
42 | return sprintf(buf, "%u\n", | ||
43 | wlp_tx_hdr_phy_rate(&options->def_tx_hdr)); | ||
44 | } | ||
45 | EXPORT_SYMBOL_GPL(uwb_phy_rate_show); | ||
46 | |||
47 | |||
48 | ssize_t uwb_phy_rate_store(struct wlp_options *options, | ||
49 | const char *buf, size_t size) | ||
50 | { | ||
51 | ssize_t result; | ||
52 | unsigned rate; | ||
53 | |||
54 | result = sscanf(buf, "%u\n", &rate); | ||
55 | if (result != 1) { | ||
56 | result = -EINVAL; | ||
57 | goto out; | ||
58 | } | ||
59 | result = -EINVAL; | ||
60 | if (rate >= UWB_PHY_RATE_INVALID) | ||
61 | goto out; | ||
62 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate); | ||
63 | result = 0; | ||
64 | out: | ||
65 | return result < 0 ? result : size; | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(uwb_phy_rate_store); | ||
68 | |||
69 | |||
70 | ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf) | ||
71 | { | ||
72 | return sprintf(buf, "%u\n", | ||
73 | wlp_tx_hdr_rts_cts(&options->def_tx_hdr)); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(uwb_rts_cts_show); | ||
76 | |||
77 | |||
78 | ssize_t uwb_rts_cts_store(struct wlp_options *options, | ||
79 | const char *buf, size_t size) | ||
80 | { | ||
81 | ssize_t result; | ||
82 | unsigned value; | ||
83 | |||
84 | result = sscanf(buf, "%u\n", &value); | ||
85 | if (result != 1) { | ||
86 | result = -EINVAL; | ||
87 | goto out; | ||
88 | } | ||
89 | result = -EINVAL; | ||
90 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value); | ||
91 | result = 0; | ||
92 | out: | ||
93 | return result < 0 ? result : size; | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(uwb_rts_cts_store); | ||
96 | |||
97 | |||
98 | ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf) | ||
99 | { | ||
100 | return sprintf(buf, "%u\n", | ||
101 | wlp_tx_hdr_ack_policy(&options->def_tx_hdr)); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(uwb_ack_policy_show); | ||
104 | |||
105 | |||
106 | ssize_t uwb_ack_policy_store(struct wlp_options *options, | ||
107 | const char *buf, size_t size) | ||
108 | { | ||
109 | ssize_t result; | ||
110 | unsigned value; | ||
111 | |||
112 | result = sscanf(buf, "%u\n", &value); | ||
113 | if (result != 1 || value > UWB_ACK_B_REQ) { | ||
114 | result = -EINVAL; | ||
115 | goto out; | ||
116 | } | ||
117 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value); | ||
118 | result = 0; | ||
119 | out: | ||
120 | return result < 0 ? result : size; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(uwb_ack_policy_store); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Show the PCA base priority. | ||
127 | * | ||
128 | * We can access without locking, as the value is (for now) orthogonal | ||
129 | * to other values. | ||
130 | */ | ||
131 | ssize_t uwb_pca_base_priority_show(const struct wlp_options *options, | ||
132 | char *buf) | ||
133 | { | ||
134 | return sprintf(buf, "%u\n", | ||
135 | options->pca_base_priority); | ||
136 | } | ||
137 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show); | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Set the PCA base priority. | ||
142 | * | ||
143 | * We can access without locking, as the value is (for now) orthogonal | ||
144 | * to other values. | ||
145 | */ | ||
146 | ssize_t uwb_pca_base_priority_store(struct wlp_options *options, | ||
147 | const char *buf, size_t size) | ||
148 | { | ||
149 | ssize_t result = -EINVAL; | ||
150 | u8 pca_base_priority; | ||
151 | |||
152 | result = sscanf(buf, "%hhu\n", &pca_base_priority); | ||
153 | if (result != 1) { | ||
154 | result = -EINVAL; | ||
155 | goto out; | ||
156 | } | ||
157 | result = -EINVAL; | ||
158 | if (pca_base_priority >= 8) | ||
159 | goto out; | ||
160 | options->pca_base_priority = pca_base_priority; | ||
161 | /* Update TX header if we are currently using PCA. */ | ||
162 | if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0) | ||
163 | wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority); | ||
164 | result = 0; | ||
165 | out: | ||
166 | return result < 0 ? result : size; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store); | ||
169 | |||
170 | /** | ||
171 | * Show current inflight values | ||
172 | * | ||
173 | * Will print the current MAX and THRESHOLD values for the basic flow | ||
174 | * control. In addition it will report how many times the TX queue needed | ||
175 | * to be restarted since the last time this query was made. | ||
176 | */ | ||
177 | static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight, | ||
178 | char *buf) | ||
179 | { | ||
180 | ssize_t result; | ||
181 | unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ; | ||
182 | unsigned long restart_count = atomic_read(&inflight->restart_count); | ||
183 | |||
184 | result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n" | ||
185 | "#read: threshold max inflight_count restarts " | ||
186 | "seconds restarts/sec\n" | ||
187 | "#write: threshold max\n", | ||
188 | inflight->threshold, inflight->max, | ||
189 | atomic_read(&inflight->count), | ||
190 | restart_count, sec_elapsed, | ||
191 | sec_elapsed == 0 ? 0 : restart_count/sec_elapsed); | ||
192 | inflight->restart_ts = jiffies; | ||
193 | atomic_set(&inflight->restart_count, 0); | ||
194 | return result; | ||
195 | } | ||
196 | |||
197 | static | ||
198 | ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight, | ||
199 | const char *buf, size_t size) | ||
200 | { | ||
201 | unsigned long in_threshold, in_max; | ||
202 | ssize_t result; | ||
203 | result = sscanf(buf, "%lu %lu", &in_threshold, &in_max); | ||
204 | if (result != 2) | ||
205 | return -EINVAL; | ||
206 | if (in_max <= in_threshold) | ||
207 | return -EINVAL; | ||
208 | inflight->max = in_max; | ||
209 | inflight->threshold = in_threshold; | ||
210 | return size; | ||
211 | } | ||
212 | /* | ||
213 | * Glue (or function adaptors) for accesing info on sysfs | ||
214 | * | ||
215 | * [we need this indirection because the PCI driver does almost the | ||
216 | * same] | ||
217 | * | ||
218 | * Linux 2.6.21 changed how 'struct netdevice' does attributes (from | ||
219 | * having a 'struct class_dev' to having a 'struct device'). That is | ||
220 | * quite of a pain. | ||
221 | * | ||
222 | * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE() | ||
223 | * create adaptors for extracting the 'struct i1480u' from a 'struct | ||
224 | * dev' and calling a function for doing a sysfs operation (as we have | ||
225 | * them factorized already). i1480u_ATTR creates the attribute file | ||
226 | * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a | ||
227 | * class_device_attr_NAME or device_attr_NAME (for group registration). | ||
228 | */ | ||
229 | #include <linux/version.h> | ||
230 | |||
231 | #define i1480u_SHOW(name, fn, param) \ | ||
232 | static ssize_t i1480u_show_##name(struct device *dev, \ | ||
233 | struct device_attribute *attr,\ | ||
234 | char *buf) \ | ||
235 | { \ | ||
236 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
237 | return fn(&i1480u->param, buf); \ | ||
238 | } | ||
239 | |||
240 | #define i1480u_STORE(name, fn, param) \ | ||
241 | static ssize_t i1480u_store_##name(struct device *dev, \ | ||
242 | struct device_attribute *attr,\ | ||
243 | const char *buf, size_t size)\ | ||
244 | { \ | ||
245 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
246 | return fn(&i1480u->param, buf, size); \ | ||
247 | } | ||
248 | |||
249 | #define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \ | ||
250 | i1480u_show_##name,\ | ||
251 | i1480u_store_##name) | ||
252 | |||
253 | #define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \ | ||
254 | S_IRUGO, \ | ||
255 | i1480u_show_##name, NULL) | ||
256 | |||
257 | #define i1480u_ATTR_NAME(a) (dev_attr_##a) | ||
258 | |||
259 | |||
260 | /* | ||
261 | * Sysfs adaptors | ||
262 | */ | ||
263 | i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options); | ||
264 | i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options); | ||
265 | i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR); | ||
266 | |||
267 | i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options); | ||
268 | i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options); | ||
269 | i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR); | ||
270 | |||
271 | i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options); | ||
272 | i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options); | ||
273 | i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR); | ||
274 | |||
275 | i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options); | ||
276 | i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options); | ||
277 | i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR); | ||
278 | |||
279 | i1480u_SHOW(wlp_eda, wlp_eda_show, wlp); | ||
280 | i1480u_STORE(wlp_eda, wlp_eda_store, wlp); | ||
281 | i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR); | ||
282 | |||
283 | i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp); | ||
284 | i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp); | ||
285 | i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR); | ||
286 | |||
287 | i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp); | ||
288 | i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp); | ||
289 | i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR); | ||
290 | |||
291 | i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp); | ||
292 | i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp); | ||
293 | i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR); | ||
294 | |||
295 | i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp); | ||
296 | i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp); | ||
297 | i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR); | ||
298 | |||
299 | i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp); | ||
300 | i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp); | ||
301 | i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR); | ||
302 | |||
303 | i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp); | ||
304 | i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp); | ||
305 | i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR); | ||
306 | |||
307 | i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp); | ||
308 | i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp); | ||
309 | i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR); | ||
310 | |||
311 | i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp); | ||
312 | i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp); | ||
313 | i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR); | ||
314 | |||
315 | i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp); | ||
316 | i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp); | ||
317 | i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR); | ||
318 | |||
319 | i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp); | ||
320 | i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp); | ||
321 | i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR); | ||
322 | |||
323 | i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp); | ||
324 | i1480u_ATTR_SHOW(wlp_neighborhood); | ||
325 | |||
326 | i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss); | ||
327 | i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss); | ||
328 | i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR); | ||
329 | |||
330 | /* | ||
331 | * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over | ||
332 | * the last 256 received WLP frames (ECMA-368 13.3). | ||
333 | * | ||
334 | * [the -7dB that have to be substracted from the LQI to make the LQE | ||
335 | * are already taken into account]. | ||
336 | */ | ||
337 | i1480u_SHOW(wlp_lqe, stats_show, lqe_stats); | ||
338 | i1480u_STORE(wlp_lqe, stats_store, lqe_stats); | ||
339 | i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR); | ||
340 | |||
341 | /* | ||
342 | * Show the Receive Signal Strength Indicator averaged over all the | ||
343 | * received WLP frames (ECMA-368 13.3). Still is not clear what | ||
344 | * this value is, but is kind of a percentage of the signal strength | ||
345 | * at the antenna. | ||
346 | */ | ||
347 | i1480u_SHOW(wlp_rssi, stats_show, rssi_stats); | ||
348 | i1480u_STORE(wlp_rssi, stats_store, rssi_stats); | ||
349 | i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR); | ||
350 | |||
351 | /** | ||
352 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
353 | * outstanding. Only allow "max" | ||
354 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
355 | * stopped. The queue will be restarted when there are | ||
356 | * "threshold" URBs outstanding. | ||
357 | */ | ||
358 | i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight); | ||
359 | i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight); | ||
360 | i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR); | ||
361 | |||
362 | static struct attribute *i1480u_attrs[] = { | ||
363 | &i1480u_ATTR_NAME(uwb_phy_rate).attr, | ||
364 | &i1480u_ATTR_NAME(uwb_rts_cts).attr, | ||
365 | &i1480u_ATTR_NAME(uwb_ack_policy).attr, | ||
366 | &i1480u_ATTR_NAME(uwb_pca_base_priority).attr, | ||
367 | &i1480u_ATTR_NAME(wlp_lqe).attr, | ||
368 | &i1480u_ATTR_NAME(wlp_rssi).attr, | ||
369 | &i1480u_ATTR_NAME(wlp_eda).attr, | ||
370 | &i1480u_ATTR_NAME(wlp_uuid).attr, | ||
371 | &i1480u_ATTR_NAME(wlp_dev_name).attr, | ||
372 | &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr, | ||
373 | &i1480u_ATTR_NAME(wlp_dev_model_name).attr, | ||
374 | &i1480u_ATTR_NAME(wlp_dev_model_nr).attr, | ||
375 | &i1480u_ATTR_NAME(wlp_dev_serial).attr, | ||
376 | &i1480u_ATTR_NAME(wlp_dev_prim_category).attr, | ||
377 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr, | ||
378 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr, | ||
379 | &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr, | ||
380 | &i1480u_ATTR_NAME(wlp_neighborhood).attr, | ||
381 | &i1480u_ATTR_NAME(wss_activate).attr, | ||
382 | &i1480u_ATTR_NAME(wlp_tx_inflight).attr, | ||
383 | NULL, | ||
384 | }; | ||
385 | |||
386 | static struct attribute_group i1480u_attr_group = { | ||
387 | .name = NULL, /* we want them in the same directory */ | ||
388 | .attrs = i1480u_attrs, | ||
389 | }; | ||
390 | |||
391 | int i1480u_sysfs_setup(struct i1480u *i1480u) | ||
392 | { | ||
393 | int result; | ||
394 | struct device *dev = &i1480u->usb_iface->dev; | ||
395 | result = sysfs_create_group(&i1480u->net_dev->dev.kobj, | ||
396 | &i1480u_attr_group); | ||
397 | if (result < 0) | ||
398 | dev_err(dev, "cannot initialize sysfs attributes: %d\n", | ||
399 | result); | ||
400 | return result; | ||
401 | } | ||
402 | |||
403 | |||
404 | void i1480u_sysfs_release(struct i1480u *i1480u) | ||
405 | { | ||
406 | sysfs_remove_group(&i1480u->net_dev->dev.kobj, | ||
407 | &i1480u_attr_group); | ||
408 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c new file mode 100644 index 000000000000..3426bfb68240 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/tx.c | |||
@@ -0,0 +1,632 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Deal with TX (massaging data to transmit, handling it) | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Transmission engine. Get an skb, create from that a WLP transmit | ||
24 | * context, add a WLP TX header (which we keep prefilled in the | ||
25 | * device's instance), fill out the target-specific fields and | ||
26 | * fire it. | ||
27 | * | ||
28 | * ROADMAP: | ||
29 | * | ||
30 | * Entry points: | ||
31 | * | ||
32 | * i1480u_tx_release(): called by i1480u_disconnect() to release | ||
33 | * pending tx contexts. | ||
34 | * | ||
35 | * i1480u_tx_cb(): callback for TX contexts (USB URBs) | ||
36 | * i1480u_tx_destroy(): | ||
37 | * | ||
38 | * i1480u_tx_timeout(): called for timeout handling from the | ||
39 | * network stack. | ||
40 | * | ||
41 | * i1480u_hard_start_xmit(): called for transmitting an skb from | ||
42 | * the network stack. Will interact with WLP | ||
43 | * substack to verify and prepare frame. | ||
44 | * i1480u_xmit_frame(): actual transmission on hardware | ||
45 | * | ||
46 | * i1480u_tx_create() Creates TX context | ||
47 | * i1480u_tx_create_1() For packets in 1 fragment | ||
48 | * i1480u_tx_create_n() For packets in >1 fragments | ||
49 | * | ||
50 | * TODO: | ||
51 | * | ||
52 | * - FIXME: rewrite using usb_sg_*(), add asynch support to | ||
53 | * usb_sg_*(). It might not make too much sense as most of | ||
54 | * the times the MTU will be smaller than one page... | ||
55 | */ | ||
56 | |||
57 | #include "i1480u-wlp.h" | ||
58 | #define D_LOCAL 5 | ||
59 | #include <linux/uwb/debug.h> | ||
60 | |||
61 | enum { | ||
62 | /* This is only for Next and Last TX packets */ | ||
63 | i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE | ||
64 | - sizeof(struct untd_hdr_rst), | ||
65 | }; | ||
66 | |||
67 | /** Free resources allocated to a i1480u tx context. */ | ||
68 | static | ||
69 | void i1480u_tx_free(struct i1480u_tx *wtx) | ||
70 | { | ||
71 | kfree(wtx->buf); | ||
72 | if (wtx->skb) | ||
73 | dev_kfree_skb_irq(wtx->skb); | ||
74 | usb_free_urb(wtx->urb); | ||
75 | kfree(wtx); | ||
76 | } | ||
77 | |||
78 | static | ||
79 | void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */ | ||
83 | list_del(&wtx->list_node); | ||
84 | i1480u_tx_free(wtx); | ||
85 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
86 | } | ||
87 | |||
88 | static | ||
89 | void i1480u_tx_unlink_urbs(struct i1480u *i1480u) | ||
90 | { | ||
91 | unsigned long flags; | ||
92 | struct i1480u_tx *wtx, *next; | ||
93 | |||
94 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
95 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
96 | usb_unlink_urb(wtx->urb); | ||
97 | } | ||
98 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Callback for a completed tx USB URB. | ||
104 | * | ||
105 | * TODO: | ||
106 | * | ||
107 | * - FIXME: recover errors more gracefully | ||
108 | * - FIXME: handle NAKs (I dont think they come here) for flow ctl | ||
109 | */ | ||
110 | static | ||
111 | void i1480u_tx_cb(struct urb *urb) | ||
112 | { | ||
113 | struct i1480u_tx *wtx = urb->context; | ||
114 | struct i1480u *i1480u = wtx->i1480u; | ||
115 | struct net_device *net_dev = i1480u->net_dev; | ||
116 | struct device *dev = &i1480u->usb_iface->dev; | ||
117 | unsigned long flags; | ||
118 | |||
119 | switch (urb->status) { | ||
120 | case 0: | ||
121 | spin_lock_irqsave(&i1480u->lock, flags); | ||
122 | i1480u->stats.tx_packets++; | ||
123 | i1480u->stats.tx_bytes += urb->actual_length; | ||
124 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
125 | break; | ||
126 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
127 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
128 | dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status); | ||
129 | netif_stop_queue(net_dev); | ||
130 | break; | ||
131 | case -ESHUTDOWN: /* going away! */ | ||
132 | dev_dbg(dev, "notif endp: down %d\n", urb->status); | ||
133 | netif_stop_queue(net_dev); | ||
134 | break; | ||
135 | default: | ||
136 | dev_err(dev, "TX: unknown URB status %d\n", urb->status); | ||
137 | if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS, | ||
138 | EDC_ERROR_TIMEFRAME)) { | ||
139 | dev_err(dev, "TX: max acceptable errors exceeded." | ||
140 | "Reset device.\n"); | ||
141 | netif_stop_queue(net_dev); | ||
142 | i1480u_tx_unlink_urbs(i1480u); | ||
143 | wlp_reset_all(&i1480u->wlp); | ||
144 | } | ||
145 | break; | ||
146 | } | ||
147 | i1480u_tx_destroy(i1480u, wtx); | ||
148 | if (atomic_dec_return(&i1480u->tx_inflight.count) | ||
149 | <= i1480u->tx_inflight.threshold | ||
150 | && netif_queue_stopped(net_dev) | ||
151 | && i1480u->tx_inflight.threshold != 0) { | ||
152 | if (d_test(2) && printk_ratelimit()) | ||
153 | d_printf(2, dev, "Restart queue. \n"); | ||
154 | netif_start_queue(net_dev); | ||
155 | atomic_inc(&i1480u->tx_inflight.restart_count); | ||
156 | } | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Given a buffer that doesn't fit in a single fragment, create an | ||
163 | * scatter/gather structure for delivery to the USB pipe. | ||
164 | * | ||
165 | * Implements functionality of i1480u_tx_create(). | ||
166 | * | ||
167 | * @wtx: tx descriptor | ||
168 | * @skb: skb to send | ||
169 | * @gfp_mask: gfp allocation mask | ||
170 | * @returns: Pointer to @wtx if ok, NULL on error. | ||
171 | * | ||
172 | * Sorry, TOO LONG a function, but breaking it up is kind of hard | ||
173 | * | ||
174 | * This will break the buffer in chunks smaller than | ||
175 | * i1480u_MAX_FRG_SIZE (including the header) and add proper headers | ||
176 | * to each: | ||
177 | * | ||
178 | * 1st header \ | ||
179 | * i1480 tx header | fragment 1 | ||
180 | * fragment data / | ||
181 | * nxt header \ fragment 2 | ||
182 | * fragment data / | ||
183 | * .. | ||
184 | * .. | ||
185 | * last header \ fragment 3 | ||
186 | * last fragment data / | ||
187 | * | ||
188 | * This does not fill the i1480 TX header, it is left up to the | ||
189 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
190 | * | ||
191 | * This function consumes the skb unless there is an error. | ||
192 | */ | ||
193 | static | ||
194 | int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
195 | gfp_t gfp_mask) | ||
196 | { | ||
197 | int result; | ||
198 | void *pl; | ||
199 | size_t pl_size; | ||
200 | |||
201 | void *pl_itr, *buf_itr; | ||
202 | size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0; | ||
203 | struct untd_hdr_1st *untd_hdr_1st; | ||
204 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
205 | struct untd_hdr_rst *untd_hdr_rst; | ||
206 | |||
207 | wtx->skb = NULL; | ||
208 | pl = skb->data; | ||
209 | pl_itr = pl; | ||
210 | pl_size = skb->len; | ||
211 | pl_size_left = pl_size; /* payload size */ | ||
212 | /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus | ||
213 | * the headers */ | ||
214 | pl_size_1st = i1480u_MAX_FRG_SIZE | ||
215 | - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr); | ||
216 | BUG_ON(pl_size_1st > pl_size); | ||
217 | pl_size_left -= pl_size_1st; | ||
218 | /* The rest have an smaller header (no i1480 TX header). We | ||
219 | * need to break up the payload in blocks smaller than | ||
220 | * i1480u_MAX_PL_SIZE (payload excluding header). */ | ||
221 | frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE; | ||
222 | /* Allocate space for the new buffer. In this new buffer we'll | ||
223 | * place the headers followed by the data fragment, headers, | ||
224 | * data fragments, etc.. | ||
225 | */ | ||
226 | result = -ENOMEM; | ||
227 | wtx->buf_size = sizeof(*untd_hdr_1st) | ||
228 | + sizeof(*wlp_tx_hdr) | ||
229 | + frgs * sizeof(*untd_hdr_rst) | ||
230 | + pl_size; | ||
231 | wtx->buf = kmalloc(wtx->buf_size, gfp_mask); | ||
232 | if (wtx->buf == NULL) | ||
233 | goto error_buf_alloc; | ||
234 | |||
235 | buf_itr = wtx->buf; /* We got the space, let's fill it up */ | ||
236 | /* Fill 1st fragment */ | ||
237 | untd_hdr_1st = buf_itr; | ||
238 | buf_itr += sizeof(*untd_hdr_1st); | ||
239 | untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST); | ||
240 | untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0); | ||
241 | untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr)); | ||
242 | untd_hdr_1st->fragment_len = | ||
243 | cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr)); | ||
244 | memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding)); | ||
245 | /* Set up i1480 header info */ | ||
246 | wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr; | ||
247 | buf_itr += sizeof(*wlp_tx_hdr); | ||
248 | /* Copy the first fragment */ | ||
249 | memcpy(buf_itr, pl_itr, pl_size_1st); | ||
250 | pl_itr += pl_size_1st; | ||
251 | buf_itr += pl_size_1st; | ||
252 | |||
253 | /* Now do each remaining fragment */ | ||
254 | result = -EINVAL; | ||
255 | while (pl_size_left > 0) { | ||
256 | d_printf(5, NULL, "ITR HDR: pl_size_left %zu buf_itr %zu\n", | ||
257 | pl_size_left, buf_itr - wtx->buf); | ||
258 | if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf | ||
259 | > wtx->buf_size) { | ||
260 | printk(KERN_ERR "BUG: no space for header\n"); | ||
261 | goto error_bug; | ||
262 | } | ||
263 | d_printf(5, NULL, "ITR HDR 2: pl_size_left %zu buf_itr %zu\n", | ||
264 | pl_size_left, buf_itr - wtx->buf); | ||
265 | untd_hdr_rst = buf_itr; | ||
266 | buf_itr += sizeof(*untd_hdr_rst); | ||
267 | if (pl_size_left > i1480u_MAX_PL_SIZE) { | ||
268 | frg_pl_size = i1480u_MAX_PL_SIZE; | ||
269 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT); | ||
270 | } else { | ||
271 | frg_pl_size = pl_size_left; | ||
272 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST); | ||
273 | } | ||
274 | d_printf(5, NULL, | ||
275 | "ITR PL: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", | ||
276 | pl_size_left, buf_itr - wtx->buf, frg_pl_size); | ||
277 | untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0); | ||
278 | untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size); | ||
279 | untd_hdr_rst->padding = 0; | ||
280 | if (buf_itr + frg_pl_size - wtx->buf | ||
281 | > wtx->buf_size) { | ||
282 | printk(KERN_ERR "BUG: no space for payload\n"); | ||
283 | goto error_bug; | ||
284 | } | ||
285 | memcpy(buf_itr, pl_itr, frg_pl_size); | ||
286 | buf_itr += frg_pl_size; | ||
287 | pl_itr += frg_pl_size; | ||
288 | pl_size_left -= frg_pl_size; | ||
289 | d_printf(5, NULL, | ||
290 | "ITR PL 2: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", | ||
291 | pl_size_left, buf_itr - wtx->buf, frg_pl_size); | ||
292 | } | ||
293 | dev_kfree_skb_irq(skb); | ||
294 | return 0; | ||
295 | |||
296 | error_bug: | ||
297 | printk(KERN_ERR | ||
298 | "BUG: skb %u bytes\n" | ||
299 | "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n" | ||
300 | "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n", | ||
301 | skb->len, | ||
302 | frg_pl_size, i1480u_MAX_FRG_SIZE, | ||
303 | buf_itr - wtx->buf, wtx->buf_size, pl_size_left); | ||
304 | |||
305 | kfree(wtx->buf); | ||
306 | error_buf_alloc: | ||
307 | return result; | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Given a buffer that fits in a single fragment, fill out a @wtx | ||
313 | * struct for transmitting it down the USB pipe. | ||
314 | * | ||
315 | * Uses the fact that we have space reserved in front of the skbuff | ||
316 | * for hardware headers :] | ||
317 | * | ||
318 | * This does not fill the i1480 TX header, it is left up to the | ||
319 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
320 | * | ||
321 | * @pl: pointer to payload data | ||
322 | * @pl_size: size of the payuload | ||
323 | * | ||
324 | * This function does not consume the @skb. | ||
325 | */ | ||
326 | static | ||
327 | int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
328 | gfp_t gfp_mask) | ||
329 | { | ||
330 | struct untd_hdr_cmp *untd_hdr_cmp; | ||
331 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
332 | |||
333 | wtx->buf = NULL; | ||
334 | wtx->skb = skb; | ||
335 | BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr)); | ||
336 | wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr)); | ||
337 | wtx->wlp_tx_hdr = wlp_tx_hdr; | ||
338 | BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp)); | ||
339 | untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp)); | ||
340 | |||
341 | untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP); | ||
342 | untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0); | ||
343 | untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp)); | ||
344 | untd_hdr_cmp->padding = 0; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * Given a skb to transmit, massage it to become palatable for the TX pipe | ||
351 | * | ||
352 | * This will break the buffer in chunks smaller than | ||
353 | * i1480u_MAX_FRG_SIZE and add proper headers to each. | ||
354 | * | ||
355 | * 1st header \ | ||
356 | * i1480 tx header | fragment 1 | ||
357 | * fragment data / | ||
358 | * nxt header \ fragment 2 | ||
359 | * fragment data / | ||
360 | * .. | ||
361 | * .. | ||
362 | * last header \ fragment 3 | ||
363 | * last fragment data / | ||
364 | * | ||
365 | * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE. | ||
366 | * | ||
367 | * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the | ||
368 | * following is composed: | ||
369 | * | ||
370 | * complete header \ | ||
371 | * i1480 tx header | single fragment | ||
372 | * packet data / | ||
373 | * | ||
374 | * We were going to use s/g support, but because the interface is | ||
375 | * synch and at the end there is plenty of overhead to do it, it | ||
376 | * didn't seem that worth for data that is going to be smaller than | ||
377 | * one page. | ||
378 | */ | ||
379 | static | ||
380 | struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u, | ||
381 | struct sk_buff *skb, gfp_t gfp_mask) | ||
382 | { | ||
383 | int result; | ||
384 | struct usb_endpoint_descriptor *epd; | ||
385 | int usb_pipe; | ||
386 | unsigned long flags; | ||
387 | |||
388 | struct i1480u_tx *wtx; | ||
389 | const size_t pl_max_size = | ||
390 | i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp) | ||
391 | - sizeof(struct wlp_tx_hdr); | ||
392 | |||
393 | wtx = kmalloc(sizeof(*wtx), gfp_mask); | ||
394 | if (wtx == NULL) | ||
395 | goto error_wtx_alloc; | ||
396 | wtx->urb = usb_alloc_urb(0, gfp_mask); | ||
397 | if (wtx->urb == NULL) | ||
398 | goto error_urb_alloc; | ||
399 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc; | ||
400 | usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress); | ||
401 | /* Fits in a single complete packet or need to split? */ | ||
402 | if (skb->len > pl_max_size) { | ||
403 | result = i1480u_tx_create_n(wtx, skb, gfp_mask); | ||
404 | if (result < 0) | ||
405 | goto error_create; | ||
406 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
407 | wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx); | ||
408 | } else { | ||
409 | result = i1480u_tx_create_1(wtx, skb, gfp_mask); | ||
410 | if (result < 0) | ||
411 | goto error_create; | ||
412 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
413 | skb->data, skb->len, i1480u_tx_cb, wtx); | ||
414 | } | ||
415 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
416 | list_add(&wtx->list_node, &i1480u->tx_list); | ||
417 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
418 | return wtx; | ||
419 | |||
420 | error_create: | ||
421 | kfree(wtx->urb); | ||
422 | error_urb_alloc: | ||
423 | kfree(wtx); | ||
424 | error_wtx_alloc: | ||
425 | return NULL; | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * Actual fragmentation and transmission of frame | ||
430 | * | ||
431 | * @wlp: WLP substack data structure | ||
432 | * @skb: To be transmitted | ||
433 | * @dst: Device address of destination | ||
434 | * @returns: 0 on success, <0 on failure | ||
435 | * | ||
436 | * This function can also be called directly (not just from | ||
437 | * hard_start_xmit), so we also check here if the interface is up before | ||
438 | * taking sending anything. | ||
439 | */ | ||
440 | int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, | ||
441 | struct uwb_dev_addr *dst) | ||
442 | { | ||
443 | int result = -ENXIO; | ||
444 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
445 | struct device *dev = &i1480u->usb_iface->dev; | ||
446 | struct net_device *net_dev = i1480u->net_dev; | ||
447 | struct i1480u_tx *wtx; | ||
448 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
449 | static unsigned char dev_bcast[2] = { 0xff, 0xff }; | ||
450 | #if 0 | ||
451 | int lockup = 50; | ||
452 | #endif | ||
453 | |||
454 | d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, | ||
455 | net_dev); | ||
456 | BUG_ON(i1480u->wlp.rc == NULL); | ||
457 | if ((net_dev->flags & IFF_UP) == 0) | ||
458 | goto out; | ||
459 | result = -EBUSY; | ||
460 | if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) { | ||
461 | if (d_test(2) && printk_ratelimit()) | ||
462 | d_printf(2, dev, "Max frames in flight " | ||
463 | "stopping queue.\n"); | ||
464 | netif_stop_queue(net_dev); | ||
465 | goto error_max_inflight; | ||
466 | } | ||
467 | result = -ENOMEM; | ||
468 | wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC); | ||
469 | if (unlikely(wtx == NULL)) { | ||
470 | if (printk_ratelimit()) | ||
471 | dev_err(dev, "TX: no memory for WLP TX URB," | ||
472 | "dropping packet (in flight %d)\n", | ||
473 | atomic_read(&i1480u->tx_inflight.count)); | ||
474 | netif_stop_queue(net_dev); | ||
475 | goto error_wtx_alloc; | ||
476 | } | ||
477 | wtx->i1480u = i1480u; | ||
478 | /* Fill out the i1480 header; @i1480u->def_tx_hdr read without | ||
479 | * locking. We do so because they are kind of orthogonal to | ||
480 | * each other (and thus not changed in an atomic batch). | ||
481 | * The ETH header is right after the WLP TX header. */ | ||
482 | wlp_tx_hdr = wtx->wlp_tx_hdr; | ||
483 | *wlp_tx_hdr = i1480u->options.def_tx_hdr; | ||
484 | wlp_tx_hdr->dstaddr = *dst; | ||
485 | if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast)) | ||
486 | && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) { | ||
487 | /*Broadcast message directed to DRP host. Send as best effort | ||
488 | * on PCA. */ | ||
489 | wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority); | ||
490 | } | ||
491 | |||
492 | #if 0 | ||
493 | dev_info(dev, "TX delivering skb -> USB, %zu bytes\n", skb->len); | ||
494 | dump_bytes(dev, skb->data, skb->len > 72 ? 72 : skb->len); | ||
495 | #endif | ||
496 | #if 0 | ||
497 | /* simulates a device lockup after every lockup# packets */ | ||
498 | if (lockup && ((i1480u->stats.tx_packets + 1) % lockup) == 0) { | ||
499 | /* Simulate a dropped transmit interrupt */ | ||
500 | net_dev->trans_start = jiffies; | ||
501 | netif_stop_queue(net_dev); | ||
502 | dev_err(dev, "Simulate lockup at %ld\n", jiffies); | ||
503 | return result; | ||
504 | } | ||
505 | #endif | ||
506 | |||
507 | result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */ | ||
508 | if (result < 0) { | ||
509 | dev_err(dev, "TX: cannot submit URB: %d\n", result); | ||
510 | /* We leave the freeing of skb to calling function */ | ||
511 | wtx->skb = NULL; | ||
512 | goto error_tx_urb_submit; | ||
513 | } | ||
514 | atomic_inc(&i1480u->tx_inflight.count); | ||
515 | net_dev->trans_start = jiffies; | ||
516 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
517 | net_dev, result); | ||
518 | return result; | ||
519 | |||
520 | error_tx_urb_submit: | ||
521 | i1480u_tx_destroy(i1480u, wtx); | ||
522 | error_wtx_alloc: | ||
523 | error_max_inflight: | ||
524 | out: | ||
525 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
526 | net_dev, result); | ||
527 | return result; | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Transmit an skb Called when an skbuf has to be transmitted | ||
533 | * | ||
534 | * The skb is first passed to WLP substack to ensure this is a valid | ||
535 | * frame. If valid the device address of destination will be filled and | ||
536 | * the WLP header prepended to the skb. If this step fails we fake sending | ||
537 | * the frame, if we return an error the network stack will just keep trying. | ||
538 | * | ||
539 | * Broadcast frames inside a WSS needs to be treated special as multicast is | ||
540 | * not supported. A broadcast frame is sent as unicast to each member of the | ||
541 | * WSS - this is done by the WLP substack when it finds a broadcast frame. | ||
542 | * So, we test if the WLP substack took over the skb and only transmit it | ||
543 | * if it has not (been taken over). | ||
544 | * | ||
545 | * @net_dev->xmit_lock is held | ||
546 | */ | ||
547 | int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) | ||
548 | { | ||
549 | int result; | ||
550 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
551 | struct device *dev = &i1480u->usb_iface->dev; | ||
552 | struct uwb_dev_addr dst; | ||
553 | |||
554 | d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, | ||
555 | net_dev); | ||
556 | BUG_ON(i1480u->wlp.rc == NULL); | ||
557 | if ((net_dev->flags & IFF_UP) == 0) | ||
558 | goto error; | ||
559 | result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst); | ||
560 | if (result < 0) { | ||
561 | dev_err(dev, "WLP verification of TX frame failed (%d). " | ||
562 | "Dropping packet.\n", result); | ||
563 | goto error; | ||
564 | } else if (result == 1) { | ||
565 | d_printf(6, dev, "WLP will transmit frame. \n"); | ||
566 | /* trans_start time will be set when WLP actually transmits | ||
567 | * the frame */ | ||
568 | goto out; | ||
569 | } | ||
570 | d_printf(6, dev, "Transmitting frame. \n"); | ||
571 | result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst); | ||
572 | if (result < 0) { | ||
573 | dev_err(dev, "Frame TX failed (%d).\n", result); | ||
574 | goto error; | ||
575 | } | ||
576 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
577 | net_dev, result); | ||
578 | return NETDEV_TX_OK; | ||
579 | error: | ||
580 | dev_kfree_skb_any(skb); | ||
581 | i1480u->stats.tx_dropped++; | ||
582 | out: | ||
583 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
584 | net_dev, result); | ||
585 | return NETDEV_TX_OK; | ||
586 | } | ||
587 | |||
588 | |||
589 | /** | ||
590 | * Called when a pkt transmission doesn't complete in a reasonable period | ||
591 | * Device reset may sleep - do it outside of interrupt context (delayed) | ||
592 | */ | ||
593 | void i1480u_tx_timeout(struct net_device *net_dev) | ||
594 | { | ||
595 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
596 | |||
597 | wlp_reset_all(&i1480u->wlp); | ||
598 | } | ||
599 | |||
600 | |||
601 | void i1480u_tx_release(struct i1480u *i1480u) | ||
602 | { | ||
603 | unsigned long flags; | ||
604 | struct i1480u_tx *wtx, *next; | ||
605 | int count = 0, empty; | ||
606 | |||
607 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
608 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
609 | count++; | ||
610 | usb_unlink_urb(wtx->urb); | ||
611 | } | ||
612 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
613 | count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */ | ||
614 | /* | ||
615 | * We don't like this sollution too much (dirty as it is), but | ||
616 | * it is cheaper than putting a refcount on each i1480u_tx and | ||
617 | * i1480uting for all of them to go away... | ||
618 | * | ||
619 | * Called when no more packets can be added to tx_list | ||
620 | * so can i1480ut for it to be empty. | ||
621 | */ | ||
622 | while (1) { | ||
623 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
624 | empty = list_empty(&i1480u->tx_list); | ||
625 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
626 | if (empty) | ||
627 | break; | ||
628 | count--; | ||
629 | BUG_ON(count == 0); | ||
630 | msleep(20); | ||
631 | } | ||
632 | } | ||
diff --git a/drivers/uwb/ie.c b/drivers/uwb/ie.c new file mode 100644 index 000000000000..cf6f3d152b9d --- /dev/null +++ b/drivers/uwb/ie.c | |||
@@ -0,0 +1,541 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Information Element Handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * Reinette Chatre <reinette.chatre@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * FIXME: docs | ||
25 | */ | ||
26 | |||
27 | #include "uwb-internal.h" | ||
28 | #define D_LOCAL 0 | ||
29 | #include <linux/uwb/debug.h> | ||
30 | |||
31 | /** | ||
32 | * uwb_ie_next - get the next IE in a buffer | ||
33 | * @ptr: start of the buffer containing the IE data | ||
34 | * @len: length of the buffer | ||
35 | * | ||
36 | * Both @ptr and @len are updated so subsequent calls to uwb_ie_next() | ||
37 | * will get the next IE. | ||
38 | * | ||
39 | * NULL is returned (and @ptr and @len will not be updated) if there | ||
40 | * are no more IEs in the buffer or the buffer is too short. | ||
41 | */ | ||
42 | struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len) | ||
43 | { | ||
44 | struct uwb_ie_hdr *hdr; | ||
45 | size_t ie_len; | ||
46 | |||
47 | if (*len < sizeof(struct uwb_ie_hdr)) | ||
48 | return NULL; | ||
49 | |||
50 | hdr = *ptr; | ||
51 | ie_len = sizeof(struct uwb_ie_hdr) + hdr->length; | ||
52 | |||
53 | if (*len < ie_len) | ||
54 | return NULL; | ||
55 | |||
56 | *ptr += ie_len; | ||
57 | *len -= ie_len; | ||
58 | |||
59 | return hdr; | ||
60 | } | ||
61 | EXPORT_SYMBOL_GPL(uwb_ie_next); | ||
62 | |||
63 | /** | ||
64 | * Get the IEs that a radio controller is sending in its beacon | ||
65 | * | ||
66 | * @uwb_rc: UWB Radio Controller | ||
67 | * @returns: Size read from the system | ||
68 | * | ||
69 | * We don't need to lock the uwb_rc's mutex because we don't modify | ||
70 | * anything. Once done with the iedata buffer, call | ||
71 | * uwb_rc_ie_release(iedata). Don't call kfree on it. | ||
72 | */ | ||
73 | ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie) | ||
74 | { | ||
75 | ssize_t result; | ||
76 | struct device *dev = &uwb_rc->uwb_dev.dev; | ||
77 | struct uwb_rccb *cmd = NULL; | ||
78 | struct uwb_rceb *reply = NULL; | ||
79 | struct uwb_rc_evt_get_ie *get_ie; | ||
80 | |||
81 | d_fnstart(3, dev, "(%p, %p)\n", uwb_rc, pget_ie); | ||
82 | result = -ENOMEM; | ||
83 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
84 | if (cmd == NULL) | ||
85 | goto error_kzalloc; | ||
86 | cmd->bCommandType = UWB_RC_CET_GENERAL; | ||
87 | cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE); | ||
88 | result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd), | ||
89 | UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE, | ||
90 | &reply); | ||
91 | if (result < 0) | ||
92 | goto error_cmd; | ||
93 | get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb); | ||
94 | if (result < sizeof(*get_ie)) { | ||
95 | dev_err(dev, "not enough data returned for decoding GET IE " | ||
96 | "(%zu bytes received vs %zu needed)\n", | ||
97 | result, sizeof(*get_ie)); | ||
98 | result = -EINVAL; | ||
99 | } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) { | ||
100 | dev_err(dev, "not enough data returned for decoding GET IE " | ||
101 | "payload (%zu bytes received vs %zu needed)\n", result, | ||
102 | sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)); | ||
103 | result = -EINVAL; | ||
104 | } else | ||
105 | *pget_ie = get_ie; | ||
106 | error_cmd: | ||
107 | kfree(cmd); | ||
108 | error_kzalloc: | ||
109 | d_fnend(3, dev, "(%p, %p) = %d\n", uwb_rc, pget_ie, (int)result); | ||
110 | return result; | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(uwb_rc_get_ie); | ||
113 | |||
114 | |||
115 | /* | ||
116 | * Given a pointer to an IE, print it in ASCII/hex followed by a new line | ||
117 | * | ||
118 | * @ie_hdr: pointer to the IE header. Length is in there, and it is | ||
119 | * guaranteed that the ie_hdr->length bytes following it are | ||
120 | * safely accesible. | ||
121 | * | ||
122 | * @_data: context data passed from uwb_ie_for_each(), an struct output_ctx | ||
123 | */ | ||
124 | int uwb_ie_dump_hex(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr, | ||
125 | size_t offset, void *_ctx) | ||
126 | { | ||
127 | struct uwb_buf_ctx *ctx = _ctx; | ||
128 | const u8 *pl = (void *)(ie_hdr + 1); | ||
129 | u8 pl_itr; | ||
130 | |||
131 | ctx->bytes += scnprintf(ctx->buf + ctx->bytes, ctx->size - ctx->bytes, | ||
132 | "%02x %02x ", (unsigned) ie_hdr->element_id, | ||
133 | (unsigned) ie_hdr->length); | ||
134 | pl_itr = 0; | ||
135 | while (pl_itr < ie_hdr->length && ctx->bytes < ctx->size) | ||
136 | ctx->bytes += scnprintf(ctx->buf + ctx->bytes, | ||
137 | ctx->size - ctx->bytes, | ||
138 | "%02x ", (unsigned) pl[pl_itr++]); | ||
139 | if (ctx->bytes < ctx->size) | ||
140 | ctx->buf[ctx->bytes++] = '\n'; | ||
141 | return 0; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(uwb_ie_dump_hex); | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Verify that a pointer in a buffer points to valid IE | ||
148 | * | ||
149 | * @start: pointer to start of buffer in which IE appears | ||
150 | * @itr: pointer to IE inside buffer that will be verified | ||
151 | * @top: pointer to end of buffer | ||
152 | * | ||
153 | * @returns: 0 if IE is valid, <0 otherwise | ||
154 | * | ||
155 | * Verification involves checking that the buffer can contain a | ||
156 | * header and the amount of data reported in the IE header can be found in | ||
157 | * the buffer. | ||
158 | */ | ||
159 | static | ||
160 | int uwb_rc_ie_verify(struct uwb_dev *uwb_dev, const void *start, | ||
161 | const void *itr, const void *top) | ||
162 | { | ||
163 | struct device *dev = &uwb_dev->dev; | ||
164 | const struct uwb_ie_hdr *ie_hdr; | ||
165 | |||
166 | if (top - itr < sizeof(*ie_hdr)) { | ||
167 | dev_err(dev, "Bad IE: no data to decode header " | ||
168 | "(%zu bytes left vs %zu needed) at offset %zu\n", | ||
169 | top - itr, sizeof(*ie_hdr), itr - start); | ||
170 | return -EINVAL; | ||
171 | } | ||
172 | ie_hdr = itr; | ||
173 | itr += sizeof(*ie_hdr); | ||
174 | if (top - itr < ie_hdr->length) { | ||
175 | dev_err(dev, "Bad IE: not enough data for payload " | ||
176 | "(%zu bytes left vs %zu needed) at offset %zu\n", | ||
177 | top - itr, (size_t)ie_hdr->length, | ||
178 | (void *)ie_hdr - start); | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Walk a buffer filled with consecutive IE's a buffer | ||
187 | * | ||
188 | * @uwb_dev: UWB device this IEs belong to (for err messages mainly) | ||
189 | * | ||
190 | * @fn: function to call with each IE; if it returns 0, we keep | ||
191 | * traversing the buffer. If it returns !0, we'll stop and return | ||
192 | * that value. | ||
193 | * | ||
194 | * @data: pointer passed to @fn | ||
195 | * | ||
196 | * @buf: buffer where the consecutive IEs are located | ||
197 | * | ||
198 | * @size: size of @buf | ||
199 | * | ||
200 | * Each IE is checked for basic correctness (there is space left for | ||
201 | * the header and the payload). If that test is failed, we stop | ||
202 | * processing. For every good IE, @fn is called. | ||
203 | */ | ||
204 | ssize_t uwb_ie_for_each(struct uwb_dev *uwb_dev, uwb_ie_f fn, void *data, | ||
205 | const void *buf, size_t size) | ||
206 | { | ||
207 | ssize_t result = 0; | ||
208 | const struct uwb_ie_hdr *ie_hdr; | ||
209 | const void *itr = buf, *top = itr + size; | ||
210 | |||
211 | while (itr < top) { | ||
212 | if (uwb_rc_ie_verify(uwb_dev, buf, itr, top) != 0) | ||
213 | break; | ||
214 | ie_hdr = itr; | ||
215 | itr += sizeof(*ie_hdr) + ie_hdr->length; | ||
216 | result = fn(uwb_dev, ie_hdr, itr - buf, data); | ||
217 | if (result != 0) | ||
218 | break; | ||
219 | } | ||
220 | return result; | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(uwb_ie_for_each); | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Replace all IEs currently being transmitted by a device | ||
227 | * | ||
228 | * @cmd: pointer to the SET-IE command with the IEs to set | ||
229 | * @size: size of @buf | ||
230 | */ | ||
231 | int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd) | ||
232 | { | ||
233 | int result; | ||
234 | struct device *dev = &rc->uwb_dev.dev; | ||
235 | struct uwb_rc_evt_set_ie reply; | ||
236 | |||
237 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
238 | reply.rceb.wEvent = UWB_RC_CMD_SET_IE; | ||
239 | result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb, | ||
240 | sizeof(*cmd) + le16_to_cpu(cmd->wIELength), | ||
241 | &reply.rceb, sizeof(reply)); | ||
242 | if (result < 0) | ||
243 | goto error_cmd; | ||
244 | else if (result != sizeof(reply)) { | ||
245 | dev_err(dev, "SET-IE: not enough data to decode reply " | ||
246 | "(%d bytes received vs %zu needed)\n", | ||
247 | result, sizeof(reply)); | ||
248 | result = -EIO; | ||
249 | } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
250 | dev_err(dev, "SET-IE: command execution failed: %s (%d)\n", | ||
251 | uwb_rc_strerror(reply.bResultCode), reply.bResultCode); | ||
252 | result = -EIO; | ||
253 | } else | ||
254 | result = 0; | ||
255 | error_cmd: | ||
256 | return result; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * Determine by IE id if IE is host settable | ||
261 | * WUSB 1.0 [8.6.2.8 Table 8.85] | ||
262 | * | ||
263 | * EXCEPTION: | ||
264 | * All but UWB_IE_WLP appears in Table 8.85 from WUSB 1.0. Setting this IE | ||
265 | * is required for the WLP substack to perform association with its WSS so | ||
266 | * we hope that the WUSB spec will be changed to reflect this. | ||
267 | */ | ||
268 | static | ||
269 | int uwb_rc_ie_is_host_settable(enum uwb_ie element_id) | ||
270 | { | ||
271 | if (element_id == UWB_PCA_AVAILABILITY || | ||
272 | element_id == UWB_BP_SWITCH_IE || | ||
273 | element_id == UWB_MAC_CAPABILITIES_IE || | ||
274 | element_id == UWB_PHY_CAPABILITIES_IE || | ||
275 | element_id == UWB_APP_SPEC_PROBE_IE || | ||
276 | element_id == UWB_IDENTIFICATION_IE || | ||
277 | element_id == UWB_MASTER_KEY_ID_IE || | ||
278 | element_id == UWB_IE_WLP || | ||
279 | element_id == UWB_APP_SPEC_IE) | ||
280 | return 1; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Extract Host Settable IEs from IE | ||
287 | * | ||
288 | * @ie_data: pointer to buffer containing all IEs | ||
289 | * @size: size of buffer | ||
290 | * | ||
291 | * @returns: length of buffer that only includes host settable IEs | ||
292 | * | ||
293 | * Given a buffer of IEs we move all Host Settable IEs to front of buffer | ||
294 | * by overwriting the IEs that are not Host Settable. | ||
295 | * Buffer length is adjusted accordingly. | ||
296 | */ | ||
297 | static | ||
298 | ssize_t uwb_rc_parse_host_settable_ie(struct uwb_dev *uwb_dev, | ||
299 | void *ie_data, size_t size) | ||
300 | { | ||
301 | size_t new_len = size; | ||
302 | struct uwb_ie_hdr *ie_hdr; | ||
303 | size_t ie_length; | ||
304 | void *itr = ie_data, *top = itr + size; | ||
305 | |||
306 | while (itr < top) { | ||
307 | if (uwb_rc_ie_verify(uwb_dev, ie_data, itr, top) != 0) | ||
308 | break; | ||
309 | ie_hdr = itr; | ||
310 | ie_length = sizeof(*ie_hdr) + ie_hdr->length; | ||
311 | if (uwb_rc_ie_is_host_settable(ie_hdr->element_id)) { | ||
312 | itr += ie_length; | ||
313 | } else { | ||
314 | memmove(itr, itr + ie_length, top - (itr + ie_length)); | ||
315 | new_len -= ie_length; | ||
316 | top -= ie_length; | ||
317 | } | ||
318 | } | ||
319 | return new_len; | ||
320 | } | ||
321 | |||
322 | |||
323 | /* Cleanup the whole IE management subsystem */ | ||
324 | void uwb_rc_ie_init(struct uwb_rc *uwb_rc) | ||
325 | { | ||
326 | mutex_init(&uwb_rc->ies_mutex); | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Set up cache for host settable IEs currently being transmitted | ||
332 | * | ||
333 | * First we just call GET-IE to get the current IEs being transmitted | ||
334 | * (or we workaround and pretend we did) and (because the format is | ||
335 | * the same) reuse that as the IE cache (with the command prefix, as | ||
336 | * explained in 'struct uwb_rc'). | ||
337 | * | ||
338 | * @returns: size of cache created | ||
339 | */ | ||
340 | ssize_t uwb_rc_ie_setup(struct uwb_rc *uwb_rc) | ||
341 | { | ||
342 | struct device *dev = &uwb_rc->uwb_dev.dev; | ||
343 | ssize_t result; | ||
344 | size_t capacity; | ||
345 | struct uwb_rc_evt_get_ie *ie_info; | ||
346 | |||
347 | d_fnstart(3, dev, "(%p)\n", uwb_rc); | ||
348 | mutex_lock(&uwb_rc->ies_mutex); | ||
349 | result = uwb_rc_get_ie(uwb_rc, &ie_info); | ||
350 | if (result < 0) | ||
351 | goto error_get_ie; | ||
352 | capacity = result; | ||
353 | d_printf(5, dev, "Got IEs %zu bytes (%zu long at %p)\n", result, | ||
354 | (size_t)le16_to_cpu(ie_info->wIELength), ie_info); | ||
355 | |||
356 | /* Remove IEs that host should not set. */ | ||
357 | result = uwb_rc_parse_host_settable_ie(&uwb_rc->uwb_dev, | ||
358 | ie_info->IEData, le16_to_cpu(ie_info->wIELength)); | ||
359 | if (result < 0) | ||
360 | goto error_parse; | ||
361 | d_printf(5, dev, "purged non-settable IEs to %zu bytes\n", result); | ||
362 | uwb_rc->ies = (void *) ie_info; | ||
363 | uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
364 | uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE); | ||
365 | uwb_rc->ies_capacity = capacity; | ||
366 | d_printf(5, dev, "IE cache at %p %zu bytes, %zu capacity\n", | ||
367 | ie_info, result, capacity); | ||
368 | result = 0; | ||
369 | error_parse: | ||
370 | error_get_ie: | ||
371 | mutex_unlock(&uwb_rc->ies_mutex); | ||
372 | d_fnend(3, dev, "(%p) = %zu\n", uwb_rc, result); | ||
373 | return result; | ||
374 | } | ||
375 | |||
376 | |||
377 | /* Cleanup the whole IE management subsystem */ | ||
378 | void uwb_rc_ie_release(struct uwb_rc *uwb_rc) | ||
379 | { | ||
380 | kfree(uwb_rc->ies); | ||
381 | uwb_rc->ies = NULL; | ||
382 | uwb_rc->ies_capacity = 0; | ||
383 | } | ||
384 | |||
385 | |||
386 | static | ||
387 | int __acc_size(struct uwb_dev *uwb_dev, const struct uwb_ie_hdr *ie_hdr, | ||
388 | size_t offset, void *_ctx) | ||
389 | { | ||
390 | size_t *acc_size = _ctx; | ||
391 | *acc_size += sizeof(*ie_hdr) + ie_hdr->length; | ||
392 | d_printf(6, &uwb_dev->dev, "new acc size %zu\n", *acc_size); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Add a new IE to IEs currently being transmitted by device | ||
399 | * | ||
400 | * @ies: the buffer containing the new IE or IEs to be added to | ||
401 | * the device's beacon. The buffer will be verified for | ||
402 | * consistence (meaning the headers should be right) and | ||
403 | * consistent with the buffer size. | ||
404 | * @size: size of @ies (in bytes, total buffer size) | ||
405 | * @returns: 0 if ok, <0 errno code on error | ||
406 | * | ||
407 | * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB | ||
408 | * after the device sent the first beacon that includes the IEs specified | ||
409 | * in the SET IE command. We thus cannot send this command if the device is | ||
410 | * not beaconing. Instead, a SET IE command will be sent later right after | ||
411 | * we start beaconing. | ||
412 | * | ||
413 | * Setting an IE on the device will overwrite all current IEs in device. So | ||
414 | * we take the current IEs being transmitted by the device, append the | ||
415 | * new one, and call SET IE with all the IEs needed. | ||
416 | * | ||
417 | * The local IE cache will only be updated with the new IE if SET IE | ||
418 | * completed successfully. | ||
419 | */ | ||
420 | int uwb_rc_ie_add(struct uwb_rc *uwb_rc, | ||
421 | const struct uwb_ie_hdr *ies, size_t size) | ||
422 | { | ||
423 | int result = 0; | ||
424 | struct device *dev = &uwb_rc->uwb_dev.dev; | ||
425 | struct uwb_rc_cmd_set_ie *new_ies; | ||
426 | size_t ies_size, total_size, acc_size = 0; | ||
427 | |||
428 | if (uwb_rc->ies == NULL) | ||
429 | return -ESHUTDOWN; | ||
430 | uwb_ie_for_each(&uwb_rc->uwb_dev, __acc_size, &acc_size, ies, size); | ||
431 | if (acc_size != size) { | ||
432 | dev_err(dev, "BUG: bad IEs, misconstructed headers " | ||
433 | "[%zu bytes reported vs %zu calculated]\n", | ||
434 | size, acc_size); | ||
435 | WARN_ON(1); | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | mutex_lock(&uwb_rc->ies_mutex); | ||
439 | ies_size = le16_to_cpu(uwb_rc->ies->wIELength); | ||
440 | total_size = sizeof(*uwb_rc->ies) + ies_size; | ||
441 | if (total_size + size > uwb_rc->ies_capacity) { | ||
442 | d_printf(4, dev, "Reallocating IE cache from %p capacity %zu " | ||
443 | "to capacity %zu\n", uwb_rc->ies, uwb_rc->ies_capacity, | ||
444 | total_size + size); | ||
445 | new_ies = kzalloc(total_size + size, GFP_KERNEL); | ||
446 | if (new_ies == NULL) { | ||
447 | dev_err(dev, "No memory for adding new IE\n"); | ||
448 | result = -ENOMEM; | ||
449 | goto error_alloc; | ||
450 | } | ||
451 | memcpy(new_ies, uwb_rc->ies, total_size); | ||
452 | uwb_rc->ies_capacity = total_size + size; | ||
453 | kfree(uwb_rc->ies); | ||
454 | uwb_rc->ies = new_ies; | ||
455 | d_printf(4, dev, "New IE cache at %p capacity %zu\n", | ||
456 | uwb_rc->ies, uwb_rc->ies_capacity); | ||
457 | } | ||
458 | memcpy((void *)uwb_rc->ies + total_size, ies, size); | ||
459 | uwb_rc->ies->wIELength = cpu_to_le16(ies_size + size); | ||
460 | if (uwb_rc->beaconing != -1) { | ||
461 | result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); | ||
462 | if (result < 0) { | ||
463 | dev_err(dev, "Cannot set new IE on device: %d\n", | ||
464 | result); | ||
465 | uwb_rc->ies->wIELength = cpu_to_le16(ies_size); | ||
466 | } else | ||
467 | result = 0; | ||
468 | } | ||
469 | d_printf(4, dev, "IEs now occupy %hu bytes of %zu capacity at %p\n", | ||
470 | le16_to_cpu(uwb_rc->ies->wIELength), uwb_rc->ies_capacity, | ||
471 | uwb_rc->ies); | ||
472 | error_alloc: | ||
473 | mutex_unlock(&uwb_rc->ies_mutex); | ||
474 | return result; | ||
475 | } | ||
476 | EXPORT_SYMBOL_GPL(uwb_rc_ie_add); | ||
477 | |||
478 | |||
479 | /* | ||
480 | * Remove an IE from internal cache | ||
481 | * | ||
482 | * We are dealing with our internal IE cache so no need to verify that the | ||
483 | * IEs are valid (it has been done already). | ||
484 | * | ||
485 | * Should be called with ies_mutex held | ||
486 | * | ||
487 | * We do not break out once an IE is found in the cache. It is currently | ||
488 | * possible to have more than one IE with the same ID included in the | ||
489 | * beacon. We don't reallocate, we just mark the size smaller. | ||
490 | */ | ||
491 | static | ||
492 | int uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove) | ||
493 | { | ||
494 | struct uwb_ie_hdr *ie_hdr; | ||
495 | size_t new_len = le16_to_cpu(uwb_rc->ies->wIELength); | ||
496 | void *itr = uwb_rc->ies->IEData; | ||
497 | void *top = itr + new_len; | ||
498 | |||
499 | while (itr < top) { | ||
500 | ie_hdr = itr; | ||
501 | if (ie_hdr->element_id != to_remove) { | ||
502 | itr += sizeof(*ie_hdr) + ie_hdr->length; | ||
503 | } else { | ||
504 | int ie_length; | ||
505 | ie_length = sizeof(*ie_hdr) + ie_hdr->length; | ||
506 | if (top - itr != ie_length) | ||
507 | memmove(itr, itr + ie_length, top - itr + ie_length); | ||
508 | top -= ie_length; | ||
509 | new_len -= ie_length; | ||
510 | } | ||
511 | } | ||
512 | uwb_rc->ies->wIELength = cpu_to_le16(new_len); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | |||
517 | /** | ||
518 | * Remove an IE currently being transmitted by device | ||
519 | * | ||
520 | * @element_id: id of IE to be removed from device's beacon | ||
521 | */ | ||
522 | int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id) | ||
523 | { | ||
524 | struct device *dev = &uwb_rc->uwb_dev.dev; | ||
525 | int result; | ||
526 | |||
527 | if (uwb_rc->ies == NULL) | ||
528 | return -ESHUTDOWN; | ||
529 | mutex_lock(&uwb_rc->ies_mutex); | ||
530 | result = uwb_rc_ie_cache_rm(uwb_rc, element_id); | ||
531 | if (result < 0) | ||
532 | dev_err(dev, "Cannot remove IE from cache.\n"); | ||
533 | if (uwb_rc->beaconing != -1) { | ||
534 | result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); | ||
535 | if (result < 0) | ||
536 | dev_err(dev, "Cannot set new IE on device.\n"); | ||
537 | } | ||
538 | mutex_unlock(&uwb_rc->ies_mutex); | ||
539 | return result; | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(uwb_rc_ie_rm); | ||
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c new file mode 100644 index 000000000000..15f856c9689a --- /dev/null +++ b/drivers/uwb/lc-dev.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Life cycle of devices | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/kdev_t.h> | ||
30 | #include <linux/random.h> | ||
31 | #include "uwb-internal.h" | ||
32 | |||
33 | #define D_LOCAL 1 | ||
34 | #include <linux/uwb/debug.h> | ||
35 | |||
36 | |||
37 | /* We initialize addresses to 0xff (invalid, as it is bcast) */ | ||
38 | static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr) | ||
39 | { | ||
40 | memset(&addr->data, 0xff, sizeof(addr->data)); | ||
41 | } | ||
42 | |||
43 | static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr) | ||
44 | { | ||
45 | memset(&addr->data, 0xff, sizeof(addr->data)); | ||
46 | } | ||
47 | |||
48 | /* @returns !0 if a device @addr is a broadcast address */ | ||
49 | static inline int uwb_dev_addr_bcast(const struct uwb_dev_addr *addr) | ||
50 | { | ||
51 | static const struct uwb_dev_addr bcast = { .data = { 0xff, 0xff } }; | ||
52 | return !uwb_dev_addr_cmp(addr, &bcast); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Add callback @new to be called when an event occurs in @rc. | ||
57 | */ | ||
58 | int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new) | ||
59 | { | ||
60 | if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) | ||
61 | return -ERESTARTSYS; | ||
62 | list_add(&new->list_node, &rc->notifs_chain.list); | ||
63 | mutex_unlock(&rc->notifs_chain.mutex); | ||
64 | return 0; | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(uwb_notifs_register); | ||
67 | |||
68 | /* | ||
69 | * Remove event handler (callback) | ||
70 | */ | ||
71 | int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry) | ||
72 | { | ||
73 | if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) | ||
74 | return -ERESTARTSYS; | ||
75 | list_del(&entry->list_node); | ||
76 | mutex_unlock(&rc->notifs_chain.mutex); | ||
77 | return 0; | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(uwb_notifs_deregister); | ||
80 | |||
81 | /* | ||
82 | * Notify all event handlers of a given event on @rc | ||
83 | * | ||
84 | * We are called with a valid reference to the device, or NULL if the | ||
85 | * event is not for a particular event (e.g., a BG join event). | ||
86 | */ | ||
87 | void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event) | ||
88 | { | ||
89 | struct uwb_notifs_handler *handler; | ||
90 | if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) | ||
91 | return; | ||
92 | if (!list_empty(&rc->notifs_chain.list)) { | ||
93 | list_for_each_entry(handler, &rc->notifs_chain.list, list_node) { | ||
94 | handler->cb(handler->data, uwb_dev, event); | ||
95 | } | ||
96 | } | ||
97 | mutex_unlock(&rc->notifs_chain.mutex); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Release the backing device of a uwb_dev that has been dynamically allocated. | ||
102 | */ | ||
103 | static void uwb_dev_sys_release(struct device *dev) | ||
104 | { | ||
105 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
106 | |||
107 | d_fnstart(4, NULL, "(dev %p uwb_dev %p)\n", dev, uwb_dev); | ||
108 | uwb_bce_put(uwb_dev->bce); | ||
109 | d_printf(0, &uwb_dev->dev, "uwb_dev %p freed\n", uwb_dev); | ||
110 | memset(uwb_dev, 0x69, sizeof(*uwb_dev)); | ||
111 | kfree(uwb_dev); | ||
112 | d_fnend(4, NULL, "(dev %p uwb_dev %p) = void\n", dev, uwb_dev); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Initialize a UWB device instance | ||
117 | * | ||
118 | * Alloc, zero and call this function. | ||
119 | */ | ||
120 | void uwb_dev_init(struct uwb_dev *uwb_dev) | ||
121 | { | ||
122 | mutex_init(&uwb_dev->mutex); | ||
123 | device_initialize(&uwb_dev->dev); | ||
124 | uwb_dev->dev.release = uwb_dev_sys_release; | ||
125 | uwb_dev_addr_init(&uwb_dev->dev_addr); | ||
126 | uwb_mac_addr_init(&uwb_dev->mac_addr); | ||
127 | bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS); | ||
128 | } | ||
129 | |||
130 | static ssize_t uwb_dev_EUI_48_show(struct device *dev, | ||
131 | struct device_attribute *attr, char *buf) | ||
132 | { | ||
133 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
134 | char addr[UWB_ADDR_STRSIZE]; | ||
135 | |||
136 | uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr); | ||
137 | return sprintf(buf, "%s\n", addr); | ||
138 | } | ||
139 | static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL); | ||
140 | |||
141 | static ssize_t uwb_dev_DevAddr_show(struct device *dev, | ||
142 | struct device_attribute *attr, char *buf) | ||
143 | { | ||
144 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
145 | char addr[UWB_ADDR_STRSIZE]; | ||
146 | |||
147 | uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr); | ||
148 | return sprintf(buf, "%s\n", addr); | ||
149 | } | ||
150 | static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL); | ||
151 | |||
152 | /* | ||
153 | * Show the BPST of this device. | ||
154 | * | ||
155 | * Calculated from the receive time of the device's beacon and it's | ||
156 | * slot number. | ||
157 | */ | ||
158 | static ssize_t uwb_dev_BPST_show(struct device *dev, | ||
159 | struct device_attribute *attr, char *buf) | ||
160 | { | ||
161 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
162 | struct uwb_beca_e *bce; | ||
163 | struct uwb_beacon_frame *bf; | ||
164 | u16 bpst; | ||
165 | |||
166 | bce = uwb_dev->bce; | ||
167 | mutex_lock(&bce->mutex); | ||
168 | bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo; | ||
169 | bpst = bce->be->wBPSTOffset | ||
170 | - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US); | ||
171 | mutex_unlock(&bce->mutex); | ||
172 | |||
173 | return sprintf(buf, "%d\n", bpst); | ||
174 | } | ||
175 | static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL); | ||
176 | |||
177 | /* | ||
178 | * Show the IEs a device is beaconing | ||
179 | * | ||
180 | * We need to access the beacon cache, so we just lock it really | ||
181 | * quick, print the IEs and unlock. | ||
182 | * | ||
183 | * We have a reference on the cache entry, so that should be | ||
184 | * quite safe. | ||
185 | */ | ||
186 | static ssize_t uwb_dev_IEs_show(struct device *dev, | ||
187 | struct device_attribute *attr, char *buf) | ||
188 | { | ||
189 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
190 | |||
191 | return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE); | ||
192 | } | ||
193 | static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL); | ||
194 | |||
195 | static ssize_t uwb_dev_LQE_show(struct device *dev, | ||
196 | struct device_attribute *attr, char *buf) | ||
197 | { | ||
198 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
199 | struct uwb_beca_e *bce = uwb_dev->bce; | ||
200 | size_t result; | ||
201 | |||
202 | mutex_lock(&bce->mutex); | ||
203 | result = stats_show(&uwb_dev->bce->lqe_stats, buf); | ||
204 | mutex_unlock(&bce->mutex); | ||
205 | return result; | ||
206 | } | ||
207 | |||
208 | static ssize_t uwb_dev_LQE_store(struct device *dev, | ||
209 | struct device_attribute *attr, | ||
210 | const char *buf, size_t size) | ||
211 | { | ||
212 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
213 | struct uwb_beca_e *bce = uwb_dev->bce; | ||
214 | ssize_t result; | ||
215 | |||
216 | mutex_lock(&bce->mutex); | ||
217 | result = stats_store(&uwb_dev->bce->lqe_stats, buf, size); | ||
218 | mutex_unlock(&bce->mutex); | ||
219 | return result; | ||
220 | } | ||
221 | static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store); | ||
222 | |||
223 | static ssize_t uwb_dev_RSSI_show(struct device *dev, | ||
224 | struct device_attribute *attr, char *buf) | ||
225 | { | ||
226 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
227 | struct uwb_beca_e *bce = uwb_dev->bce; | ||
228 | size_t result; | ||
229 | |||
230 | mutex_lock(&bce->mutex); | ||
231 | result = stats_show(&uwb_dev->bce->rssi_stats, buf); | ||
232 | mutex_unlock(&bce->mutex); | ||
233 | return result; | ||
234 | } | ||
235 | |||
236 | static ssize_t uwb_dev_RSSI_store(struct device *dev, | ||
237 | struct device_attribute *attr, | ||
238 | const char *buf, size_t size) | ||
239 | { | ||
240 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
241 | struct uwb_beca_e *bce = uwb_dev->bce; | ||
242 | ssize_t result; | ||
243 | |||
244 | mutex_lock(&bce->mutex); | ||
245 | result = stats_store(&uwb_dev->bce->rssi_stats, buf, size); | ||
246 | mutex_unlock(&bce->mutex); | ||
247 | return result; | ||
248 | } | ||
249 | static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store); | ||
250 | |||
251 | |||
252 | static struct attribute *dev_attrs[] = { | ||
253 | &dev_attr_EUI_48.attr, | ||
254 | &dev_attr_DevAddr.attr, | ||
255 | &dev_attr_BPST.attr, | ||
256 | &dev_attr_IEs.attr, | ||
257 | &dev_attr_LQE.attr, | ||
258 | &dev_attr_RSSI.attr, | ||
259 | NULL, | ||
260 | }; | ||
261 | |||
262 | static struct attribute_group dev_attr_group = { | ||
263 | .attrs = dev_attrs, | ||
264 | }; | ||
265 | |||
266 | static struct attribute_group *groups[] = { | ||
267 | &dev_attr_group, | ||
268 | NULL, | ||
269 | }; | ||
270 | |||
271 | /** | ||
272 | * Device SYSFS registration | ||
273 | * | ||
274 | * | ||
275 | */ | ||
276 | static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev) | ||
277 | { | ||
278 | int result; | ||
279 | struct device *dev; | ||
280 | |||
281 | d_fnstart(4, NULL, "(uwb_dev %p parent_dev %p)\n", uwb_dev, parent_dev); | ||
282 | BUG_ON(parent_dev == NULL); | ||
283 | |||
284 | dev = &uwb_dev->dev; | ||
285 | /* Device sysfs files are only useful for neighbor devices not | ||
286 | local radio controllers. */ | ||
287 | if (&uwb_dev->rc->uwb_dev != uwb_dev) | ||
288 | dev->groups = groups; | ||
289 | dev->parent = parent_dev; | ||
290 | dev_set_drvdata(dev, uwb_dev); | ||
291 | |||
292 | result = device_add(dev); | ||
293 | d_fnend(4, NULL, "(uwb_dev %p parent_dev %p) = %d\n", uwb_dev, parent_dev, result); | ||
294 | return result; | ||
295 | } | ||
296 | |||
297 | |||
298 | static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev) | ||
299 | { | ||
300 | d_fnstart(4, NULL, "(uwb_dev %p)\n", uwb_dev); | ||
301 | dev_set_drvdata(&uwb_dev->dev, NULL); | ||
302 | device_del(&uwb_dev->dev); | ||
303 | d_fnend(4, NULL, "(uwb_dev %p) = void\n", uwb_dev); | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Register and initialize a new UWB device | ||
309 | * | ||
310 | * Did you call uwb_dev_init() on it? | ||
311 | * | ||
312 | * @parent_rc: is the parent radio controller who has the link to the | ||
313 | * device. When registering the UWB device that is a UWB | ||
314 | * Radio Controller, we point back to it. | ||
315 | * | ||
316 | * If registering the device that is part of a radio, caller has set | ||
317 | * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will | ||
318 | * be allocated. | ||
319 | */ | ||
320 | int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev, | ||
321 | struct uwb_rc *parent_rc) | ||
322 | { | ||
323 | int result; | ||
324 | struct device *dev; | ||
325 | |||
326 | BUG_ON(uwb_dev == NULL); | ||
327 | BUG_ON(parent_dev == NULL); | ||
328 | BUG_ON(parent_rc == NULL); | ||
329 | |||
330 | mutex_lock(&uwb_dev->mutex); | ||
331 | dev = &uwb_dev->dev; | ||
332 | uwb_dev->rc = parent_rc; | ||
333 | result = __uwb_dev_sys_add(uwb_dev, parent_dev); | ||
334 | if (result < 0) | ||
335 | printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n", | ||
336 | dev_name(dev), result); | ||
337 | mutex_unlock(&uwb_dev->mutex); | ||
338 | return result; | ||
339 | } | ||
340 | |||
341 | |||
342 | void uwb_dev_rm(struct uwb_dev *uwb_dev) | ||
343 | { | ||
344 | mutex_lock(&uwb_dev->mutex); | ||
345 | __uwb_dev_sys_rm(uwb_dev); | ||
346 | mutex_unlock(&uwb_dev->mutex); | ||
347 | } | ||
348 | |||
349 | |||
350 | static | ||
351 | int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev) | ||
352 | { | ||
353 | struct uwb_dev *target_uwb_dev = __target_uwb_dev; | ||
354 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
355 | if (uwb_dev == target_uwb_dev) { | ||
356 | uwb_dev_get(uwb_dev); | ||
357 | return 1; | ||
358 | } else | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | |||
363 | /** | ||
364 | * Given a UWB device descriptor, validate and refcount it | ||
365 | * | ||
366 | * @returns NULL if the device does not exist or is quiescing; the ptr to | ||
367 | * it otherwise. | ||
368 | */ | ||
369 | struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev) | ||
370 | { | ||
371 | if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev)) | ||
372 | return uwb_dev; | ||
373 | else | ||
374 | return NULL; | ||
375 | } | ||
376 | EXPORT_SYMBOL_GPL(uwb_dev_try_get); | ||
377 | |||
378 | |||
379 | /** | ||
380 | * Remove a device from the system [grunt for other functions] | ||
381 | */ | ||
382 | int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc) | ||
383 | { | ||
384 | struct device *dev = &uwb_dev->dev; | ||
385 | char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; | ||
386 | |||
387 | d_fnstart(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p)\n", dev, uwb_dev, rc); | ||
388 | uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr); | ||
389 | uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr); | ||
390 | dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n", | ||
391 | macbuf, devbuf, | ||
392 | rc ? rc->uwb_dev.dev.parent->bus->name : "n/a", | ||
393 | rc ? dev_name(rc->uwb_dev.dev.parent) : ""); | ||
394 | uwb_dev_rm(uwb_dev); | ||
395 | uwb_dev_put(uwb_dev); /* for the creation in _onair() */ | ||
396 | d_fnend(3, NULL, "(dev %p [uwb_dev %p], uwb_rc %p) = 0\n", dev, uwb_dev, rc); | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | |||
401 | /** | ||
402 | * A device went off the air, clean up after it! | ||
403 | * | ||
404 | * This is called by the UWB Daemon (through the beacon purge function | ||
405 | * uwb_bcn_cache_purge) when it is detected that a device has been in | ||
406 | * radio silence for a while. | ||
407 | * | ||
408 | * If this device is actually a local radio controller we don't need | ||
409 | * to go through the offair process, as it is not registered as that. | ||
410 | * | ||
411 | * NOTE: uwb_bcn_cache.mutex is held! | ||
412 | */ | ||
413 | void uwbd_dev_offair(struct uwb_beca_e *bce) | ||
414 | { | ||
415 | struct uwb_dev *uwb_dev; | ||
416 | |||
417 | uwb_dev = bce->uwb_dev; | ||
418 | if (uwb_dev) { | ||
419 | uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR); | ||
420 | __uwb_dev_offair(uwb_dev, uwb_dev->rc); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * A device went on the air, start it up! | ||
427 | * | ||
428 | * This is called by the UWB Daemon when it is detected that a device | ||
429 | * has popped up in the radio range of the radio controller. | ||
430 | * | ||
431 | * It will just create the freaking device, register the beacon and | ||
432 | * stuff and yatla, done. | ||
433 | * | ||
434 | * | ||
435 | * NOTE: uwb_beca.mutex is held, bce->mutex is held | ||
436 | */ | ||
437 | void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce) | ||
438 | { | ||
439 | int result; | ||
440 | struct device *dev = &rc->uwb_dev.dev; | ||
441 | struct uwb_dev *uwb_dev; | ||
442 | char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; | ||
443 | |||
444 | uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr); | ||
445 | uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr); | ||
446 | uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL); | ||
447 | if (uwb_dev == NULL) { | ||
448 | dev_err(dev, "new device %s: Cannot allocate memory\n", | ||
449 | macbuf); | ||
450 | return; | ||
451 | } | ||
452 | uwb_dev_init(uwb_dev); /* This sets refcnt to one, we own it */ | ||
453 | uwb_dev->mac_addr = *bce->mac_addr; | ||
454 | uwb_dev->dev_addr = bce->dev_addr; | ||
455 | dev_set_name(&uwb_dev->dev, macbuf); | ||
456 | result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc); | ||
457 | if (result < 0) { | ||
458 | dev_err(dev, "new device %s: cannot instantiate device\n", | ||
459 | macbuf); | ||
460 | goto error_dev_add; | ||
461 | } | ||
462 | /* plug the beacon cache */ | ||
463 | bce->uwb_dev = uwb_dev; | ||
464 | uwb_dev->bce = bce; | ||
465 | uwb_bce_get(bce); /* released in uwb_dev_sys_release() */ | ||
466 | dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n", | ||
467 | macbuf, devbuf, rc->uwb_dev.dev.parent->bus->name, | ||
468 | dev_name(rc->uwb_dev.dev.parent)); | ||
469 | uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR); | ||
470 | return; | ||
471 | |||
472 | error_dev_add: | ||
473 | kfree(uwb_dev); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * Iterate over the list of UWB devices, calling a @function on each | ||
479 | * | ||
480 | * See docs for bus_for_each().... | ||
481 | * | ||
482 | * @rc: radio controller for the devices. | ||
483 | * @function: function to call. | ||
484 | * @priv: data to pass to @function. | ||
485 | * @returns: 0 if no invocation of function() returned a value | ||
486 | * different to zero. That value otherwise. | ||
487 | */ | ||
488 | int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv) | ||
489 | { | ||
490 | return device_for_each_child(&rc->uwb_dev.dev, priv, function); | ||
491 | } | ||
492 | EXPORT_SYMBOL_GPL(uwb_dev_for_each); | ||
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c new file mode 100644 index 000000000000..ee5772f00d42 --- /dev/null +++ b/drivers/uwb/lc-rc.c | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Life cycle of radio controllers | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * A UWB radio controller is also a UWB device, so it embeds one... | ||
26 | * | ||
27 | * List of RCs comes from the 'struct class uwb_rc_class'. | ||
28 | */ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/err.h> | ||
34 | #include <linux/random.h> | ||
35 | #include <linux/kdev_t.h> | ||
36 | #include <linux/etherdevice.h> | ||
37 | #include <linux/usb.h> | ||
38 | |||
39 | #define D_LOCAL 1 | ||
40 | #include <linux/uwb/debug.h> | ||
41 | #include "uwb-internal.h" | ||
42 | |||
43 | static int uwb_rc_index_match(struct device *dev, void *data) | ||
44 | { | ||
45 | int *index = data; | ||
46 | struct uwb_rc *rc = dev_get_drvdata(dev); | ||
47 | |||
48 | if (rc->index == *index) | ||
49 | return 1; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static struct uwb_rc *uwb_rc_find_by_index(int index) | ||
54 | { | ||
55 | struct device *dev; | ||
56 | struct uwb_rc *rc = NULL; | ||
57 | |||
58 | dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match); | ||
59 | if (dev) | ||
60 | rc = dev_get_drvdata(dev); | ||
61 | return rc; | ||
62 | } | ||
63 | |||
64 | static int uwb_rc_new_index(void) | ||
65 | { | ||
66 | int index = 0; | ||
67 | |||
68 | for (;;) { | ||
69 | if (!uwb_rc_find_by_index(index)) | ||
70 | return index; | ||
71 | if (++index < 0) | ||
72 | index = 0; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Release the backing device of a uwb_rc that has been dynamically allocated. | ||
78 | */ | ||
79 | static void uwb_rc_sys_release(struct device *dev) | ||
80 | { | ||
81 | struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev); | ||
82 | struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev); | ||
83 | |||
84 | uwb_rc_neh_destroy(rc); | ||
85 | uwb_rc_ie_release(rc); | ||
86 | d_printf(1, dev, "freed uwb_rc %p\n", rc); | ||
87 | kfree(rc); | ||
88 | } | ||
89 | |||
90 | |||
91 | void uwb_rc_init(struct uwb_rc *rc) | ||
92 | { | ||
93 | struct uwb_dev *uwb_dev = &rc->uwb_dev; | ||
94 | |||
95 | uwb_dev_init(uwb_dev); | ||
96 | rc->uwb_dev.dev.class = &uwb_rc_class; | ||
97 | rc->uwb_dev.dev.release = uwb_rc_sys_release; | ||
98 | uwb_rc_neh_create(rc); | ||
99 | rc->beaconing = -1; | ||
100 | rc->scan_type = UWB_SCAN_DISABLED; | ||
101 | INIT_LIST_HEAD(&rc->notifs_chain.list); | ||
102 | mutex_init(&rc->notifs_chain.mutex); | ||
103 | uwb_drp_avail_init(rc); | ||
104 | uwb_rc_ie_init(rc); | ||
105 | uwb_rsv_init(rc); | ||
106 | uwb_rc_pal_init(rc); | ||
107 | } | ||
108 | EXPORT_SYMBOL_GPL(uwb_rc_init); | ||
109 | |||
110 | |||
111 | struct uwb_rc *uwb_rc_alloc(void) | ||
112 | { | ||
113 | struct uwb_rc *rc; | ||
114 | rc = kzalloc(sizeof(*rc), GFP_KERNEL); | ||
115 | if (rc == NULL) | ||
116 | return NULL; | ||
117 | uwb_rc_init(rc); | ||
118 | return rc; | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(uwb_rc_alloc); | ||
121 | |||
122 | static struct attribute *rc_attrs[] = { | ||
123 | &dev_attr_mac_address.attr, | ||
124 | &dev_attr_scan.attr, | ||
125 | &dev_attr_beacon.attr, | ||
126 | NULL, | ||
127 | }; | ||
128 | |||
129 | static struct attribute_group rc_attr_group = { | ||
130 | .attrs = rc_attrs, | ||
131 | }; | ||
132 | |||
133 | /* | ||
134 | * Registration of sysfs specific stuff | ||
135 | */ | ||
136 | static int uwb_rc_sys_add(struct uwb_rc *rc) | ||
137 | { | ||
138 | return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group); | ||
139 | } | ||
140 | |||
141 | |||
142 | static void __uwb_rc_sys_rm(struct uwb_rc *rc) | ||
143 | { | ||
144 | sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it | ||
149 | * @rc: the radio controller. | ||
150 | * | ||
151 | * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF | ||
152 | * then a random locally administered EUI-48 is generated and set on | ||
153 | * the device. The probability of address collisions is sufficiently | ||
154 | * unlikely (1/2^40 = 9.1e-13) that they're not checked for. | ||
155 | */ | ||
156 | static | ||
157 | int uwb_rc_mac_addr_setup(struct uwb_rc *rc) | ||
158 | { | ||
159 | int result; | ||
160 | struct device *dev = &rc->uwb_dev.dev; | ||
161 | struct uwb_dev *uwb_dev = &rc->uwb_dev; | ||
162 | char devname[UWB_ADDR_STRSIZE]; | ||
163 | struct uwb_mac_addr addr; | ||
164 | |||
165 | result = uwb_rc_mac_addr_get(rc, &addr); | ||
166 | if (result < 0) { | ||
167 | dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result); | ||
168 | return result; | ||
169 | } | ||
170 | |||
171 | if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) { | ||
172 | addr.data[0] = 0x02; /* locally adminstered and unicast */ | ||
173 | get_random_bytes(&addr.data[1], sizeof(addr.data)-1); | ||
174 | |||
175 | result = uwb_rc_mac_addr_set(rc, &addr); | ||
176 | if (result < 0) { | ||
177 | uwb_mac_addr_print(devname, sizeof(devname), &addr); | ||
178 | dev_err(dev, "cannot set EUI-48 address %s: %d\n", | ||
179 | devname, result); | ||
180 | return result; | ||
181 | } | ||
182 | } | ||
183 | uwb_dev->mac_addr = addr; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | |||
188 | |||
189 | static int uwb_rc_setup(struct uwb_rc *rc) | ||
190 | { | ||
191 | int result; | ||
192 | struct device *dev = &rc->uwb_dev.dev; | ||
193 | |||
194 | result = uwb_rc_reset(rc); | ||
195 | if (result < 0) { | ||
196 | dev_err(dev, "cannot reset UWB radio: %d\n", result); | ||
197 | goto error; | ||
198 | } | ||
199 | result = uwb_rc_mac_addr_setup(rc); | ||
200 | if (result < 0) { | ||
201 | dev_err(dev, "cannot setup UWB MAC address: %d\n", result); | ||
202 | goto error; | ||
203 | } | ||
204 | result = uwb_rc_dev_addr_assign(rc); | ||
205 | if (result < 0) { | ||
206 | dev_err(dev, "cannot assign UWB DevAddr: %d\n", result); | ||
207 | goto error; | ||
208 | } | ||
209 | result = uwb_rc_ie_setup(rc); | ||
210 | if (result < 0) { | ||
211 | dev_err(dev, "cannot setup IE subsystem: %d\n", result); | ||
212 | goto error_ie_setup; | ||
213 | } | ||
214 | result = uwb_rsv_setup(rc); | ||
215 | if (result < 0) { | ||
216 | dev_err(dev, "cannot setup reservation subsystem: %d\n", result); | ||
217 | goto error_rsv_setup; | ||
218 | } | ||
219 | uwb_dbg_add_rc(rc); | ||
220 | return 0; | ||
221 | |||
222 | error_rsv_setup: | ||
223 | uwb_rc_ie_release(rc); | ||
224 | error_ie_setup: | ||
225 | error: | ||
226 | return result; | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Register a new UWB radio controller | ||
232 | * | ||
233 | * Did you call uwb_rc_init() on your rc? | ||
234 | * | ||
235 | * We assume that this is being called with a > 0 refcount on | ||
236 | * it [through ops->{get|put}_device(). We'll take our own, though. | ||
237 | * | ||
238 | * @parent_dev is our real device, the one that provides the actual UWB device | ||
239 | */ | ||
240 | int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv) | ||
241 | { | ||
242 | int result; | ||
243 | struct device *dev; | ||
244 | char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; | ||
245 | |||
246 | rc->index = uwb_rc_new_index(); | ||
247 | |||
248 | dev = &rc->uwb_dev.dev; | ||
249 | dev_set_name(dev, "uwb%d", rc->index); | ||
250 | |||
251 | rc->priv = priv; | ||
252 | |||
253 | result = rc->start(rc); | ||
254 | if (result < 0) | ||
255 | goto error_rc_start; | ||
256 | |||
257 | result = uwb_rc_setup(rc); | ||
258 | if (result < 0) { | ||
259 | dev_err(dev, "cannot setup UWB radio controller: %d\n", result); | ||
260 | goto error_rc_setup; | ||
261 | } | ||
262 | |||
263 | result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc); | ||
264 | if (result < 0 && result != -EADDRNOTAVAIL) | ||
265 | goto error_dev_add; | ||
266 | |||
267 | result = uwb_rc_sys_add(rc); | ||
268 | if (result < 0) { | ||
269 | dev_err(parent_dev, "cannot register UWB radio controller " | ||
270 | "dev attributes: %d\n", result); | ||
271 | goto error_sys_add; | ||
272 | } | ||
273 | |||
274 | uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr); | ||
275 | uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr); | ||
276 | dev_info(dev, | ||
277 | "new uwb radio controller (mac %s dev %s) on %s %s\n", | ||
278 | macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev)); | ||
279 | rc->ready = 1; | ||
280 | return 0; | ||
281 | |||
282 | error_sys_add: | ||
283 | uwb_dev_rm(&rc->uwb_dev); | ||
284 | error_dev_add: | ||
285 | error_rc_setup: | ||
286 | rc->stop(rc); | ||
287 | uwbd_flush(rc); | ||
288 | error_rc_start: | ||
289 | return result; | ||
290 | } | ||
291 | EXPORT_SYMBOL_GPL(uwb_rc_add); | ||
292 | |||
293 | |||
294 | static int uwb_dev_offair_helper(struct device *dev, void *priv) | ||
295 | { | ||
296 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
297 | |||
298 | return __uwb_dev_offair(uwb_dev, uwb_dev->rc); | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Remove a Radio Controller; stop beaconing/scanning, disconnect all children | ||
303 | */ | ||
304 | void uwb_rc_rm(struct uwb_rc *rc) | ||
305 | { | ||
306 | rc->ready = 0; | ||
307 | |||
308 | uwb_dbg_del_rc(rc); | ||
309 | uwb_rsv_cleanup(rc); | ||
310 | uwb_rc_ie_rm(rc, UWB_IDENTIFICATION_IE); | ||
311 | if (rc->beaconing >= 0) | ||
312 | uwb_rc_beacon(rc, -1, 0); | ||
313 | if (rc->scan_type != UWB_SCAN_DISABLED) | ||
314 | uwb_rc_scan(rc, rc->scanning, UWB_SCAN_DISABLED, 0); | ||
315 | uwb_rc_reset(rc); | ||
316 | |||
317 | rc->stop(rc); | ||
318 | uwbd_flush(rc); | ||
319 | |||
320 | uwb_dev_lock(&rc->uwb_dev); | ||
321 | rc->priv = NULL; | ||
322 | rc->cmd = NULL; | ||
323 | uwb_dev_unlock(&rc->uwb_dev); | ||
324 | mutex_lock(&uwb_beca.mutex); | ||
325 | uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL); | ||
326 | __uwb_rc_sys_rm(rc); | ||
327 | mutex_unlock(&uwb_beca.mutex); | ||
328 | uwb_dev_rm(&rc->uwb_dev); | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(uwb_rc_rm); | ||
331 | |||
332 | static int find_rc_try_get(struct device *dev, void *data) | ||
333 | { | ||
334 | struct uwb_rc *target_rc = data; | ||
335 | struct uwb_rc *rc = dev_get_drvdata(dev); | ||
336 | |||
337 | if (rc == NULL) { | ||
338 | WARN_ON(1); | ||
339 | return 0; | ||
340 | } | ||
341 | if (rc == target_rc) { | ||
342 | if (rc->ready == 0) | ||
343 | return 0; | ||
344 | else | ||
345 | return 1; | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Given a radio controller descriptor, validate and refcount it | ||
352 | * | ||
353 | * @returns NULL if the rc does not exist or is quiescing; the ptr to | ||
354 | * it otherwise. | ||
355 | */ | ||
356 | struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc) | ||
357 | { | ||
358 | struct device *dev; | ||
359 | struct uwb_rc *rc = NULL; | ||
360 | |||
361 | dev = class_find_device(&uwb_rc_class, NULL, target_rc, | ||
362 | find_rc_try_get); | ||
363 | if (dev) { | ||
364 | rc = dev_get_drvdata(dev); | ||
365 | __uwb_rc_get(rc); | ||
366 | } | ||
367 | return rc; | ||
368 | } | ||
369 | EXPORT_SYMBOL_GPL(__uwb_rc_try_get); | ||
370 | |||
371 | /* | ||
372 | * RC get for external refcount acquirers... | ||
373 | * | ||
374 | * Increments the refcount of the device and it's backend modules | ||
375 | */ | ||
376 | static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc) | ||
377 | { | ||
378 | if (rc->ready == 0) | ||
379 | return NULL; | ||
380 | uwb_dev_get(&rc->uwb_dev); | ||
381 | return rc; | ||
382 | } | ||
383 | |||
384 | static int find_rc_grandpa(struct device *dev, void *data) | ||
385 | { | ||
386 | struct device *grandpa_dev = data; | ||
387 | struct uwb_rc *rc = dev_get_drvdata(dev); | ||
388 | |||
389 | if (rc->uwb_dev.dev.parent->parent == grandpa_dev) { | ||
390 | rc = uwb_rc_get(rc); | ||
391 | return 1; | ||
392 | } | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * Locate and refcount a radio controller given a common grand-parent | ||
398 | * | ||
399 | * @grandpa_dev Pointer to the 'grandparent' device structure. | ||
400 | * @returns NULL If the rc does not exist or is quiescing; the ptr to | ||
401 | * it otherwise, properly referenced. | ||
402 | * | ||
403 | * The Radio Control interface (or the UWB Radio Controller) is always | ||
404 | * an interface of a device. The parent is the interface, the | ||
405 | * grandparent is the device that encapsulates the interface. | ||
406 | * | ||
407 | * There is no need to lock around as the "grandpa" would be | ||
408 | * refcounted by the target, and to remove the referemes, the | ||
409 | * uwb_rc_class->sem would have to be taken--we hold it, ergo we | ||
410 | * should be safe. | ||
411 | */ | ||
412 | struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev) | ||
413 | { | ||
414 | struct device *dev; | ||
415 | struct uwb_rc *rc = NULL; | ||
416 | |||
417 | dev = class_find_device(&uwb_rc_class, NULL, (void *)grandpa_dev, | ||
418 | find_rc_grandpa); | ||
419 | if (dev) | ||
420 | rc = dev_get_drvdata(dev); | ||
421 | return rc; | ||
422 | } | ||
423 | EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa); | ||
424 | |||
425 | /** | ||
426 | * Find a radio controller by device address | ||
427 | * | ||
428 | * @returns the pointer to the radio controller, properly referenced | ||
429 | */ | ||
430 | static int find_rc_dev(struct device *dev, void *data) | ||
431 | { | ||
432 | struct uwb_dev_addr *addr = data; | ||
433 | struct uwb_rc *rc = dev_get_drvdata(dev); | ||
434 | |||
435 | if (rc == NULL) { | ||
436 | WARN_ON(1); | ||
437 | return 0; | ||
438 | } | ||
439 | if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) { | ||
440 | rc = uwb_rc_get(rc); | ||
441 | return 1; | ||
442 | } | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr) | ||
447 | { | ||
448 | struct device *dev; | ||
449 | struct uwb_rc *rc = NULL; | ||
450 | |||
451 | dev = class_find_device(&uwb_rc_class, NULL, (void *)addr, | ||
452 | find_rc_dev); | ||
453 | if (dev) | ||
454 | rc = dev_get_drvdata(dev); | ||
455 | |||
456 | return rc; | ||
457 | } | ||
458 | EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev); | ||
459 | |||
460 | /** | ||
461 | * Drop a reference on a radio controller | ||
462 | * | ||
463 | * This is the version that should be done by entities external to the | ||
464 | * UWB Radio Control stack (ie: clients of the API). | ||
465 | */ | ||
466 | void uwb_rc_put(struct uwb_rc *rc) | ||
467 | { | ||
468 | __uwb_rc_put(rc); | ||
469 | } | ||
470 | EXPORT_SYMBOL_GPL(uwb_rc_put); | ||
471 | |||
472 | /* | ||
473 | * | ||
474 | * | ||
475 | */ | ||
476 | ssize_t uwb_rc_print_IEs(struct uwb_rc *uwb_rc, char *buf, size_t size) | ||
477 | { | ||
478 | ssize_t result; | ||
479 | struct uwb_rc_evt_get_ie *ie_info; | ||
480 | struct uwb_buf_ctx ctx; | ||
481 | |||
482 | result = uwb_rc_get_ie(uwb_rc, &ie_info); | ||
483 | if (result < 0) | ||
484 | goto error_get_ie; | ||
485 | ctx.buf = buf; | ||
486 | ctx.size = size; | ||
487 | ctx.bytes = 0; | ||
488 | uwb_ie_for_each(&uwb_rc->uwb_dev, uwb_ie_dump_hex, &ctx, | ||
489 | ie_info->IEData, result - sizeof(*ie_info)); | ||
490 | result = ctx.bytes; | ||
491 | kfree(ie_info); | ||
492 | error_get_ie: | ||
493 | return result; | ||
494 | } | ||
495 | |||
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c new file mode 100644 index 000000000000..9b4eb64327ac --- /dev/null +++ b/drivers/uwb/neh.c | |||
@@ -0,0 +1,616 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: Radio Control Interface (WUSB[8]) | ||
3 | * Notification and Event Handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI | ||
24 | * card delivers a stream of notifications and events to the | ||
25 | * notification end event endpoint or area. This code takes care of | ||
26 | * getting a buffer with that data, breaking it up in separate | ||
27 | * notifications and events and then deliver those. | ||
28 | * | ||
29 | * Events are answers to commands and they carry a context ID that | ||
30 | * associates them to the command. Notifications are that, | ||
31 | * notifications, they come out of the blue and have a context ID of | ||
32 | * zero. Think of the context ID kind of like a handler. The | ||
33 | * uwb_rc_neh_* code deals with managing context IDs. | ||
34 | * | ||
35 | * This is why you require a handle to operate on a UWB host. When you | ||
36 | * open a handle a context ID is assigned to you. | ||
37 | * | ||
38 | * So, as it is done is: | ||
39 | * | ||
40 | * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id) | ||
41 | * 2. Issue command [rc->cmd(rc, ...)] | ||
42 | * 3. Arm the timeout timer [uwb_rc_neh_arm()] | ||
43 | * 4, Release the reference to the neh [uwb_rc_neh_put()] | ||
44 | * 5. Wait for the callback | ||
45 | * 6. Command result (RCEB) is passed to the callback | ||
46 | * | ||
47 | * If (2) fails, you should remove the handle [uwb_rc_neh_rm()] | ||
48 | * instead of arming the timer. | ||
49 | * | ||
50 | * Handles are for using in *serialized* code, single thread. | ||
51 | * | ||
52 | * When the notification/event comes, the IRQ handler/endpoint | ||
53 | * callback passes the data read to uwb_rc_neh_grok() which will break | ||
54 | * it up in a discrete series of events, look up who is listening for | ||
55 | * them and execute the pertinent callbacks. | ||
56 | * | ||
57 | * If the reader detects an error while reading the data stream, call | ||
58 | * uwb_rc_neh_error(). | ||
59 | * | ||
60 | * CONSTRAINTS/ASSUMPTIONS: | ||
61 | * | ||
62 | * - Most notifications/events are small (less thank .5k), copying | ||
63 | * around is ok. | ||
64 | * | ||
65 | * - Notifications/events are ALWAYS smaller than PAGE_SIZE | ||
66 | * | ||
67 | * - Notifications/events always come in a single piece (ie: a buffer | ||
68 | * will always contain entire notifications/events). | ||
69 | * | ||
70 | * - we cannot know in advance how long each event is (because they | ||
71 | * lack a length field in their header--smart move by the standards | ||
72 | * body, btw). So we need a facility to get the event size given the | ||
73 | * header. This is what the EST code does (notif/Event Size | ||
74 | * Tables), check nest.c--as well, you can associate the size to | ||
75 | * the handle [w/ neh->extra_size()]. | ||
76 | * | ||
77 | * - Most notifications/events are fixed size; only a few are variable | ||
78 | * size (NEST takes care of that). | ||
79 | * | ||
80 | * - Listeners of events expect them, so they usually provide a | ||
81 | * buffer, as they know the size. Listeners to notifications don't, | ||
82 | * so we allocate their buffers dynamically. | ||
83 | */ | ||
84 | #include <linux/kernel.h> | ||
85 | #include <linux/timer.h> | ||
86 | #include <linux/err.h> | ||
87 | |||
88 | #include "uwb-internal.h" | ||
89 | #define D_LOCAL 0 | ||
90 | #include <linux/uwb/debug.h> | ||
91 | |||
92 | /* | ||
93 | * UWB Radio Controller Notification/Event Handle | ||
94 | * | ||
95 | * Represents an entity waiting for an event coming from the UWB Radio | ||
96 | * Controller with a given context id (context) and type (evt_type and | ||
97 | * evt). On reception of the notification/event, the callback (cb) is | ||
98 | * called with the event. | ||
99 | * | ||
100 | * If the timer expires before the event is received, the callback is | ||
101 | * called with -ETIMEDOUT as the event size. | ||
102 | */ | ||
103 | struct uwb_rc_neh { | ||
104 | struct kref kref; | ||
105 | |||
106 | struct uwb_rc *rc; | ||
107 | u8 evt_type; | ||
108 | __le16 evt; | ||
109 | u8 context; | ||
110 | uwb_rc_cmd_cb_f cb; | ||
111 | void *arg; | ||
112 | |||
113 | struct timer_list timer; | ||
114 | struct list_head list_node; | ||
115 | }; | ||
116 | |||
117 | static void uwb_rc_neh_timer(unsigned long arg); | ||
118 | |||
119 | static void uwb_rc_neh_release(struct kref *kref) | ||
120 | { | ||
121 | struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref); | ||
122 | |||
123 | kfree(neh); | ||
124 | } | ||
125 | |||
126 | static void uwb_rc_neh_get(struct uwb_rc_neh *neh) | ||
127 | { | ||
128 | kref_get(&neh->kref); | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * uwb_rc_neh_put - release reference to a neh | ||
133 | * @neh: the neh | ||
134 | */ | ||
135 | void uwb_rc_neh_put(struct uwb_rc_neh *neh) | ||
136 | { | ||
137 | kref_put(&neh->kref, uwb_rc_neh_release); | ||
138 | } | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Assigns @neh a context id from @rc's pool | ||
143 | * | ||
144 | * @rc: UWB Radio Controller descriptor; @rc->neh_lock taken | ||
145 | * @neh: Notification/Event Handle | ||
146 | * @returns 0 if context id was assigned ok; < 0 errno on error (if | ||
147 | * all the context IDs are taken). | ||
148 | * | ||
149 | * (assumes @wa is locked). | ||
150 | * | ||
151 | * NOTE: WUSB spec reserves context ids 0x00 for notifications and | ||
152 | * 0xff is invalid, so they must not be used. Initialization | ||
153 | * fills up those two in the bitmap so they are not allocated. | ||
154 | * | ||
155 | * We spread the allocation around to reduce the posiblity of two | ||
156 | * consecutive opened @neh's getting the same context ID assigned (to | ||
157 | * avoid surprises with late events that timed out long time ago). So | ||
158 | * first we search from where @rc->ctx_roll is, if not found, we | ||
159 | * search from zero. | ||
160 | */ | ||
161 | static | ||
162 | int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh) | ||
163 | { | ||
164 | int result; | ||
165 | result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX, | ||
166 | rc->ctx_roll++); | ||
167 | if (result < UWB_RC_CTX_MAX) | ||
168 | goto found; | ||
169 | result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX); | ||
170 | if (result < UWB_RC_CTX_MAX) | ||
171 | goto found; | ||
172 | return -ENFILE; | ||
173 | found: | ||
174 | set_bit(result, rc->ctx_bm); | ||
175 | neh->context = result; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | |||
180 | /** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */ | ||
181 | static | ||
182 | void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh) | ||
183 | { | ||
184 | struct device *dev = &rc->uwb_dev.dev; | ||
185 | if (neh->context == 0) | ||
186 | return; | ||
187 | if (test_bit(neh->context, rc->ctx_bm) == 0) { | ||
188 | dev_err(dev, "context %u not set in bitmap\n", | ||
189 | neh->context); | ||
190 | WARN_ON(1); | ||
191 | } | ||
192 | clear_bit(neh->context, rc->ctx_bm); | ||
193 | neh->context = 0; | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * uwb_rc_neh_add - add a neh for a radio controller command | ||
198 | * @rc: the radio controller | ||
199 | * @cmd: the radio controller command | ||
200 | * @expected_type: the type of the expected response event | ||
201 | * @expected_event: the expected event ID | ||
202 | * @cb: callback for when the event is received | ||
203 | * @arg: argument for the callback | ||
204 | * | ||
205 | * Creates a neh and adds it to the list of those waiting for an | ||
206 | * event. A context ID will be assigned to the command. | ||
207 | */ | ||
208 | struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd, | ||
209 | u8 expected_type, u16 expected_event, | ||
210 | uwb_rc_cmd_cb_f cb, void *arg) | ||
211 | { | ||
212 | int result; | ||
213 | unsigned long flags; | ||
214 | struct device *dev = &rc->uwb_dev.dev; | ||
215 | struct uwb_rc_neh *neh; | ||
216 | |||
217 | neh = kzalloc(sizeof(*neh), GFP_KERNEL); | ||
218 | if (neh == NULL) { | ||
219 | result = -ENOMEM; | ||
220 | goto error_kzalloc; | ||
221 | } | ||
222 | |||
223 | kref_init(&neh->kref); | ||
224 | INIT_LIST_HEAD(&neh->list_node); | ||
225 | init_timer(&neh->timer); | ||
226 | neh->timer.function = uwb_rc_neh_timer; | ||
227 | neh->timer.data = (unsigned long)neh; | ||
228 | |||
229 | neh->rc = rc; | ||
230 | neh->evt_type = expected_type; | ||
231 | neh->evt = cpu_to_le16(expected_event); | ||
232 | neh->cb = cb; | ||
233 | neh->arg = arg; | ||
234 | |||
235 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
236 | result = __uwb_rc_ctx_get(rc, neh); | ||
237 | if (result >= 0) { | ||
238 | cmd->bCommandContext = neh->context; | ||
239 | list_add_tail(&neh->list_node, &rc->neh_list); | ||
240 | uwb_rc_neh_get(neh); | ||
241 | } | ||
242 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
243 | if (result < 0) | ||
244 | goto error_ctx_get; | ||
245 | |||
246 | return neh; | ||
247 | |||
248 | error_ctx_get: | ||
249 | kfree(neh); | ||
250 | error_kzalloc: | ||
251 | dev_err(dev, "cannot open handle to radio controller: %d\n", result); | ||
252 | return ERR_PTR(result); | ||
253 | } | ||
254 | |||
255 | static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) | ||
256 | { | ||
257 | del_timer(&neh->timer); | ||
258 | __uwb_rc_ctx_put(rc, neh); | ||
259 | list_del(&neh->list_node); | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * uwb_rc_neh_rm - remove a neh. | ||
264 | * @rc: the radio controller | ||
265 | * @neh: the neh to remove | ||
266 | * | ||
267 | * Remove an active neh immediately instead of waiting for the event | ||
268 | * (or a time out). | ||
269 | */ | ||
270 | void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | |||
274 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
275 | __uwb_rc_neh_rm(rc, neh); | ||
276 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
277 | |||
278 | uwb_rc_neh_put(neh); | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * uwb_rc_neh_arm - arm an event handler timeout timer | ||
283 | * | ||
284 | * @rc: UWB Radio Controller | ||
285 | * @neh: Notification/event handler for @rc | ||
286 | * | ||
287 | * The timer is only armed if the neh is active. | ||
288 | */ | ||
289 | void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh) | ||
290 | { | ||
291 | unsigned long flags; | ||
292 | |||
293 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
294 | if (neh->context) | ||
295 | mod_timer(&neh->timer, | ||
296 | jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS)); | ||
297 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
298 | } | ||
299 | |||
300 | static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size) | ||
301 | { | ||
302 | (*neh->cb)(neh->rc, neh->arg, rceb, size); | ||
303 | uwb_rc_neh_put(neh); | ||
304 | } | ||
305 | |||
306 | static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb) | ||
307 | { | ||
308 | return neh->evt_type == rceb->bEventType | ||
309 | && neh->evt == rceb->wEvent | ||
310 | && neh->context == rceb->bEventContext; | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * Find the handle waiting for a RC Radio Control Event | ||
315 | * | ||
316 | * @rc: UWB Radio Controller | ||
317 | * @rceb: Pointer to the RCEB buffer | ||
318 | * @event_size: Pointer to the size of the RCEB buffer. Might be | ||
319 | * adjusted to take into account the @neh->extra_size | ||
320 | * settings. | ||
321 | * | ||
322 | * If the listener has no buffer (NULL buffer), one is allocated for | ||
323 | * the right size (the amount of data received). @neh->ptr will point | ||
324 | * to the event payload, which always starts with a 'struct | ||
325 | * uwb_rceb'. kfree() it when done. | ||
326 | */ | ||
327 | static | ||
328 | struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc, | ||
329 | const struct uwb_rceb *rceb) | ||
330 | { | ||
331 | struct uwb_rc_neh *neh = NULL, *h; | ||
332 | unsigned long flags; | ||
333 | |||
334 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
335 | |||
336 | list_for_each_entry(h, &rc->neh_list, list_node) { | ||
337 | if (uwb_rc_neh_match(h, rceb)) { | ||
338 | neh = h; | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | if (neh) | ||
344 | __uwb_rc_neh_rm(rc, neh); | ||
345 | |||
346 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
347 | |||
348 | return neh; | ||
349 | } | ||
350 | |||
351 | |||
352 | /** | ||
353 | * Process notifications coming from the radio control interface | ||
354 | * | ||
355 | * @rc: UWB Radio Control Interface descriptor | ||
356 | * @neh: Notification/Event Handler @neh->ptr points to | ||
357 | * @uwb_evt->buffer. | ||
358 | * | ||
359 | * This function is called by the event/notif handling subsystem when | ||
360 | * notifications arrive (hwarc_probe() arms a notification/event handle | ||
361 | * that calls back this function for every received notification; this | ||
362 | * function then will rearm itself). | ||
363 | * | ||
364 | * Notification data buffers are dynamically allocated by the NEH | ||
365 | * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually | ||
366 | * allocated is space to contain the notification data. | ||
367 | * | ||
368 | * Buffers are prefixed with a Radio Control Event Block (RCEB) as | ||
369 | * defined by the WUSB Wired-Adapter Radio Control interface. We | ||
370 | * just use it for the notification code. | ||
371 | * | ||
372 | * On each case statement we just transcode endianess of the different | ||
373 | * fields. We declare a pointer to a RCI definition of an event, and | ||
374 | * then to a UWB definition of the same event (which are the same, | ||
375 | * remember). Event if we use different pointers | ||
376 | */ | ||
377 | static | ||
378 | void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size) | ||
379 | { | ||
380 | struct device *dev = &rc->uwb_dev.dev; | ||
381 | struct uwb_event *uwb_evt; | ||
382 | |||
383 | if (size == -ESHUTDOWN) | ||
384 | return; | ||
385 | if (size < 0) { | ||
386 | dev_err(dev, "ignoring event with error code %zu\n", | ||
387 | size); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC); | ||
392 | if (unlikely(uwb_evt == NULL)) { | ||
393 | dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n", | ||
394 | rceb->bEventType, le16_to_cpu(rceb->wEvent), | ||
395 | rceb->bEventContext); | ||
396 | return; | ||
397 | } | ||
398 | uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */ | ||
399 | uwb_evt->ts_jiffies = jiffies; | ||
400 | uwb_evt->type = UWB_EVT_TYPE_NOTIF; | ||
401 | uwb_evt->notif.size = size; | ||
402 | uwb_evt->notif.rceb = rceb; | ||
403 | |||
404 | switch (le16_to_cpu(rceb->wEvent)) { | ||
405 | /* Trap some vendor specific events | ||
406 | * | ||
407 | * FIXME: move this to handling in ptc-est, where we | ||
408 | * register a NULL event handler for these two guys | ||
409 | * using the Intel IDs. | ||
410 | */ | ||
411 | case 0x0103: | ||
412 | dev_info(dev, "FIXME: DEVICE ADD\n"); | ||
413 | return; | ||
414 | case 0x0104: | ||
415 | dev_info(dev, "FIXME: DEVICE RM\n"); | ||
416 | return; | ||
417 | default: | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | uwbd_event_queue(uwb_evt); | ||
422 | } | ||
423 | |||
424 | static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size) | ||
425 | { | ||
426 | struct device *dev = &rc->uwb_dev.dev; | ||
427 | struct uwb_rc_neh *neh; | ||
428 | struct uwb_rceb *notif; | ||
429 | |||
430 | if (rceb->bEventContext == 0) { | ||
431 | notif = kmalloc(size, GFP_ATOMIC); | ||
432 | if (notif) { | ||
433 | memcpy(notif, rceb, size); | ||
434 | uwb_rc_notif(rc, notif, size); | ||
435 | } else | ||
436 | dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n", | ||
437 | rceb->bEventType, le16_to_cpu(rceb->wEvent), | ||
438 | rceb->bEventContext, size); | ||
439 | } else { | ||
440 | neh = uwb_rc_neh_lookup(rc, rceb); | ||
441 | if (neh) | ||
442 | uwb_rc_neh_cb(neh, rceb, size); | ||
443 | else | ||
444 | dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n", | ||
445 | rceb->bEventType, le16_to_cpu(rceb->wEvent), | ||
446 | rceb->bEventContext, size); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * Given a buffer with one or more UWB RC events/notifications, break | ||
452 | * them up and dispatch them. | ||
453 | * | ||
454 | * @rc: UWB Radio Controller | ||
455 | * @buf: Buffer with the stream of notifications/events | ||
456 | * @buf_size: Amount of data in the buffer | ||
457 | * | ||
458 | * Note each notification/event starts always with a 'struct | ||
459 | * uwb_rceb', so the minimum size if 4 bytes. | ||
460 | * | ||
461 | * The device may pass us events formatted differently than expected. | ||
462 | * These are first filtered, potentially creating a new event in a new | ||
463 | * memory location. If a new event is created by the filter it is also | ||
464 | * freed here. | ||
465 | * | ||
466 | * For each notif/event, tries to guess the size looking at the EST | ||
467 | * tables, then looks for a neh that is waiting for that event and if | ||
468 | * found, copies the payload to the neh's buffer and calls it back. If | ||
469 | * not, the data is ignored. | ||
470 | * | ||
471 | * Note that if we can't find a size description in the EST tables, we | ||
472 | * still might find a size in the 'neh' handle in uwb_rc_neh_lookup(). | ||
473 | * | ||
474 | * Assumptions: | ||
475 | * | ||
476 | * @rc->neh_lock is NOT taken | ||
477 | * | ||
478 | * We keep track of various sizes here: | ||
479 | * size: contains the size of the buffer that is processed for the | ||
480 | * incoming event. this buffer may contain events that are not | ||
481 | * formatted as WHCI. | ||
482 | * real_size: the actual space taken by this event in the buffer. | ||
483 | * We need to keep track of the real size of an event to be able to | ||
484 | * advance the buffer correctly. | ||
485 | * event_size: the size of the event as expected by the core layer | ||
486 | * [OR] the size of the event after filtering. if the filtering | ||
487 | * created a new event in a new memory location then this is | ||
488 | * effectively the size of a new event buffer | ||
489 | */ | ||
490 | void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size) | ||
491 | { | ||
492 | struct device *dev = &rc->uwb_dev.dev; | ||
493 | void *itr; | ||
494 | struct uwb_rceb *rceb; | ||
495 | size_t size, real_size, event_size; | ||
496 | int needtofree; | ||
497 | |||
498 | d_fnstart(3, dev, "(rc %p buf %p %zu buf_size)\n", rc, buf, buf_size); | ||
499 | d_printf(2, dev, "groking event block: %zu bytes\n", buf_size); | ||
500 | itr = buf; | ||
501 | size = buf_size; | ||
502 | while (size > 0) { | ||
503 | if (size < sizeof(*rceb)) { | ||
504 | dev_err(dev, "not enough data in event buffer to " | ||
505 | "process incoming events (%zu left, minimum is " | ||
506 | "%zu)\n", size, sizeof(*rceb)); | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | rceb = itr; | ||
511 | if (rc->filter_event) { | ||
512 | needtofree = rc->filter_event(rc, &rceb, size, | ||
513 | &real_size, &event_size); | ||
514 | if (needtofree < 0 && needtofree != -ENOANO) { | ||
515 | dev_err(dev, "BUG: Unable to filter event " | ||
516 | "(0x%02x/%04x/%02x) from " | ||
517 | "device. \n", rceb->bEventType, | ||
518 | le16_to_cpu(rceb->wEvent), | ||
519 | rceb->bEventContext); | ||
520 | break; | ||
521 | } | ||
522 | } else | ||
523 | needtofree = -ENOANO; | ||
524 | /* do real processing if there was no filtering or the | ||
525 | * filtering didn't act */ | ||
526 | if (needtofree == -ENOANO) { | ||
527 | ssize_t ret = uwb_est_find_size(rc, rceb, size); | ||
528 | if (ret < 0) | ||
529 | break; | ||
530 | if (ret > size) { | ||
531 | dev_err(dev, "BUG: hw sent incomplete event " | ||
532 | "0x%02x/%04x/%02x (%zd bytes), only got " | ||
533 | "%zu bytes. We don't handle that.\n", | ||
534 | rceb->bEventType, le16_to_cpu(rceb->wEvent), | ||
535 | rceb->bEventContext, ret, size); | ||
536 | break; | ||
537 | } | ||
538 | real_size = event_size = ret; | ||
539 | } | ||
540 | uwb_rc_neh_grok_event(rc, rceb, event_size); | ||
541 | |||
542 | if (needtofree == 1) | ||
543 | kfree(rceb); | ||
544 | |||
545 | itr += real_size; | ||
546 | size -= real_size; | ||
547 | d_printf(2, dev, "consumed %zd bytes, %zu left\n", | ||
548 | event_size, size); | ||
549 | } | ||
550 | d_fnend(3, dev, "(rc %p buf %p %zu buf_size) = void\n", rc, buf, buf_size); | ||
551 | } | ||
552 | EXPORT_SYMBOL_GPL(uwb_rc_neh_grok); | ||
553 | |||
554 | |||
555 | /** | ||
556 | * The entity that reads from the device notification/event channel has | ||
557 | * detected an error. | ||
558 | * | ||
559 | * @rc: UWB Radio Controller | ||
560 | * @error: Errno error code | ||
561 | * | ||
562 | */ | ||
563 | void uwb_rc_neh_error(struct uwb_rc *rc, int error) | ||
564 | { | ||
565 | struct uwb_rc_neh *neh, *next; | ||
566 | unsigned long flags; | ||
567 | |||
568 | BUG_ON(error >= 0); | ||
569 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
570 | list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { | ||
571 | __uwb_rc_neh_rm(rc, neh); | ||
572 | uwb_rc_neh_cb(neh, NULL, error); | ||
573 | } | ||
574 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
575 | } | ||
576 | EXPORT_SYMBOL_GPL(uwb_rc_neh_error); | ||
577 | |||
578 | |||
579 | static void uwb_rc_neh_timer(unsigned long arg) | ||
580 | { | ||
581 | struct uwb_rc_neh *neh = (struct uwb_rc_neh *)arg; | ||
582 | struct uwb_rc *rc = neh->rc; | ||
583 | unsigned long flags; | ||
584 | |||
585 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
586 | __uwb_rc_neh_rm(rc, neh); | ||
587 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
588 | |||
589 | uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT); | ||
590 | } | ||
591 | |||
592 | /** Initializes the @rc's neh subsystem | ||
593 | */ | ||
594 | void uwb_rc_neh_create(struct uwb_rc *rc) | ||
595 | { | ||
596 | spin_lock_init(&rc->neh_lock); | ||
597 | INIT_LIST_HEAD(&rc->neh_list); | ||
598 | set_bit(0, rc->ctx_bm); /* 0 is reserved (see [WUSB] table 8-65) */ | ||
599 | set_bit(0xff, rc->ctx_bm); /* and 0xff is invalid */ | ||
600 | rc->ctx_roll = 1; | ||
601 | } | ||
602 | |||
603 | |||
604 | /** Release's the @rc's neh subsystem */ | ||
605 | void uwb_rc_neh_destroy(struct uwb_rc *rc) | ||
606 | { | ||
607 | unsigned long flags; | ||
608 | struct uwb_rc_neh *neh, *next; | ||
609 | |||
610 | spin_lock_irqsave(&rc->neh_lock, flags); | ||
611 | list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { | ||
612 | __uwb_rc_neh_rm(rc, neh); | ||
613 | uwb_rc_neh_put(neh); | ||
614 | } | ||
615 | spin_unlock_irqrestore(&rc->neh_lock, flags); | ||
616 | } | ||
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c new file mode 100644 index 000000000000..1afb38eacb9a --- /dev/null +++ b/drivers/uwb/pal.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * UWB PAL support. | ||
3 | * | ||
4 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/uwb.h> | ||
20 | |||
21 | #include "uwb-internal.h" | ||
22 | |||
23 | /** | ||
24 | * uwb_pal_init - initialize a UWB PAL | ||
25 | * @pal: the PAL to initialize | ||
26 | */ | ||
27 | void uwb_pal_init(struct uwb_pal *pal) | ||
28 | { | ||
29 | INIT_LIST_HEAD(&pal->node); | ||
30 | } | ||
31 | EXPORT_SYMBOL_GPL(uwb_pal_init); | ||
32 | |||
33 | /** | ||
34 | * uwb_pal_register - register a UWB PAL | ||
35 | * @rc: the radio controller the PAL will be using | ||
36 | * @pal: the PAL | ||
37 | * | ||
38 | * The PAL must be initialized with uwb_pal_init(). | ||
39 | */ | ||
40 | int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal) | ||
41 | { | ||
42 | int ret; | ||
43 | |||
44 | if (pal->device) { | ||
45 | ret = sysfs_create_link(&pal->device->kobj, | ||
46 | &rc->uwb_dev.dev.kobj, "uwb_rc"); | ||
47 | if (ret < 0) | ||
48 | return ret; | ||
49 | ret = sysfs_create_link(&rc->uwb_dev.dev.kobj, | ||
50 | &pal->device->kobj, pal->name); | ||
51 | if (ret < 0) { | ||
52 | sysfs_remove_link(&pal->device->kobj, "uwb_rc"); | ||
53 | return ret; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | spin_lock(&rc->pal_lock); | ||
58 | list_add(&pal->node, &rc->pals); | ||
59 | spin_unlock(&rc->pal_lock); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(uwb_pal_register); | ||
64 | |||
65 | /** | ||
66 | * uwb_pal_register - unregister a UWB PAL | ||
67 | * @rc: the radio controller the PAL was using | ||
68 | * @pal: the PAL | ||
69 | */ | ||
70 | void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal) | ||
71 | { | ||
72 | spin_lock(&rc->pal_lock); | ||
73 | list_del(&pal->node); | ||
74 | spin_unlock(&rc->pal_lock); | ||
75 | |||
76 | if (pal->device) { | ||
77 | sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name); | ||
78 | sysfs_remove_link(&pal->device->kobj, "uwb_rc"); | ||
79 | } | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(uwb_pal_unregister); | ||
82 | |||
83 | /** | ||
84 | * uwb_rc_pal_init - initialize the PAL related parts of a radio controller | ||
85 | * @rc: the radio controller | ||
86 | */ | ||
87 | void uwb_rc_pal_init(struct uwb_rc *rc) | ||
88 | { | ||
89 | spin_lock_init(&rc->pal_lock); | ||
90 | INIT_LIST_HEAD(&rc->pals); | ||
91 | } | ||
diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c new file mode 100644 index 000000000000..8de856fa7958 --- /dev/null +++ b/drivers/uwb/reset.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * UWB basic command support and radio reset | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: | ||
24 | * | ||
25 | * - docs | ||
26 | * | ||
27 | * - Now we are serializing (using the uwb_dev->mutex) the command | ||
28 | * execution; it should be parallelized as much as possible some | ||
29 | * day. | ||
30 | */ | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/err.h> | ||
33 | |||
34 | #include "uwb-internal.h" | ||
35 | #define D_LOCAL 0 | ||
36 | #include <linux/uwb/debug.h> | ||
37 | |||
38 | /** | ||
39 | * Command result codes (WUSB1.0[T8-69]) | ||
40 | */ | ||
41 | static | ||
42 | const char *__strerror[] = { | ||
43 | "success", | ||
44 | "failure", | ||
45 | "hardware failure", | ||
46 | "no more slots", | ||
47 | "beacon is too large", | ||
48 | "invalid parameter", | ||
49 | "unsupported power level", | ||
50 | "time out (wa) or invalid ie data (whci)", | ||
51 | "beacon size exceeded", | ||
52 | "cancelled", | ||
53 | "invalid state", | ||
54 | "invalid size", | ||
55 | "ack not recieved", | ||
56 | "no more asie notification", | ||
57 | }; | ||
58 | |||
59 | |||
60 | /** Return a string matching the given error code */ | ||
61 | const char *uwb_rc_strerror(unsigned code) | ||
62 | { | ||
63 | if (code == 255) | ||
64 | return "time out"; | ||
65 | if (code >= ARRAY_SIZE(__strerror)) | ||
66 | return "unknown error"; | ||
67 | return __strerror[code]; | ||
68 | } | ||
69 | |||
70 | int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name, | ||
71 | struct uwb_rccb *cmd, size_t cmd_size, | ||
72 | u8 expected_type, u16 expected_event, | ||
73 | uwb_rc_cmd_cb_f cb, void *arg) | ||
74 | { | ||
75 | struct device *dev = &rc->uwb_dev.dev; | ||
76 | struct uwb_rc_neh *neh; | ||
77 | int needtofree = 0; | ||
78 | int result; | ||
79 | |||
80 | uwb_dev_lock(&rc->uwb_dev); /* Protect against rc->priv being removed */ | ||
81 | if (rc->priv == NULL) { | ||
82 | uwb_dev_unlock(&rc->uwb_dev); | ||
83 | return -ESHUTDOWN; | ||
84 | } | ||
85 | |||
86 | if (rc->filter_cmd) { | ||
87 | needtofree = rc->filter_cmd(rc, &cmd, &cmd_size); | ||
88 | if (needtofree < 0 && needtofree != -ENOANO) { | ||
89 | dev_err(dev, "%s: filter error: %d\n", | ||
90 | cmd_name, needtofree); | ||
91 | uwb_dev_unlock(&rc->uwb_dev); | ||
92 | return needtofree; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg); | ||
97 | if (IS_ERR(neh)) { | ||
98 | result = PTR_ERR(neh); | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | result = rc->cmd(rc, cmd, cmd_size); | ||
103 | uwb_dev_unlock(&rc->uwb_dev); | ||
104 | if (result < 0) | ||
105 | uwb_rc_neh_rm(rc, neh); | ||
106 | else | ||
107 | uwb_rc_neh_arm(rc, neh); | ||
108 | uwb_rc_neh_put(neh); | ||
109 | out: | ||
110 | if (needtofree == 1) | ||
111 | kfree(cmd); | ||
112 | return result < 0 ? result : 0; | ||
113 | } | ||
114 | EXPORT_SYMBOL_GPL(uwb_rc_cmd_async); | ||
115 | |||
116 | struct uwb_rc_cmd_done_params { | ||
117 | struct completion completion; | ||
118 | struct uwb_rceb *reply; | ||
119 | ssize_t reply_size; | ||
120 | }; | ||
121 | |||
122 | static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg, | ||
123 | struct uwb_rceb *reply, ssize_t reply_size) | ||
124 | { | ||
125 | struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg; | ||
126 | |||
127 | if (reply_size > 0) { | ||
128 | if (p->reply) | ||
129 | reply_size = min(p->reply_size, reply_size); | ||
130 | else | ||
131 | p->reply = kmalloc(reply_size, GFP_ATOMIC); | ||
132 | |||
133 | if (p->reply) | ||
134 | memcpy(p->reply, reply, reply_size); | ||
135 | else | ||
136 | reply_size = -ENOMEM; | ||
137 | } | ||
138 | p->reply_size = reply_size; | ||
139 | complete(&p->completion); | ||
140 | } | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Generic function for issuing commands to the Radio Control Interface | ||
145 | * | ||
146 | * @rc: UWB Radio Control descriptor | ||
147 | * @cmd_name: Name of the command being issued (for error messages) | ||
148 | * @cmd: Pointer to rccb structure containing the command; | ||
149 | * normally you embed this structure as the first member of | ||
150 | * the full command structure. | ||
151 | * @cmd_size: Size of the whole command buffer pointed to by @cmd. | ||
152 | * @reply: Pointer to where to store the reply | ||
153 | * @reply_size: @reply's size | ||
154 | * @expected_type: Expected type in the return event | ||
155 | * @expected_event: Expected event code in the return event | ||
156 | * @preply: Here a pointer to where the event data is received will | ||
157 | * be stored. Once done with the data, free with kfree(). | ||
158 | * | ||
159 | * This function is generic; it works for commands that return a fixed | ||
160 | * and known size or for commands that return a variable amount of data. | ||
161 | * | ||
162 | * If a buffer is provided, that is used, although it could be chopped | ||
163 | * to the maximum size of the buffer. If the buffer is NULL, then one | ||
164 | * be allocated in *preply with the whole contents of the reply. | ||
165 | * | ||
166 | * @rc needs to be referenced | ||
167 | */ | ||
168 | static | ||
169 | ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name, | ||
170 | struct uwb_rccb *cmd, size_t cmd_size, | ||
171 | struct uwb_rceb *reply, size_t reply_size, | ||
172 | u8 expected_type, u16 expected_event, | ||
173 | struct uwb_rceb **preply) | ||
174 | { | ||
175 | ssize_t result = 0; | ||
176 | struct device *dev = &rc->uwb_dev.dev; | ||
177 | struct uwb_rc_cmd_done_params params; | ||
178 | |||
179 | init_completion(¶ms.completion); | ||
180 | params.reply = reply; | ||
181 | params.reply_size = reply_size; | ||
182 | |||
183 | result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size, | ||
184 | expected_type, expected_event, | ||
185 | uwb_rc_cmd_done, ¶ms); | ||
186 | if (result) | ||
187 | return result; | ||
188 | |||
189 | wait_for_completion(¶ms.completion); | ||
190 | |||
191 | if (preply) | ||
192 | *preply = params.reply; | ||
193 | |||
194 | if (params.reply_size < 0) | ||
195 | dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x " | ||
196 | "reception failed: %d\n", cmd_name, | ||
197 | expected_type, expected_event, cmd->bCommandContext, | ||
198 | (int)params.reply_size); | ||
199 | return params.reply_size; | ||
200 | } | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Generic function for issuing commands to the Radio Control Interface | ||
205 | * | ||
206 | * @rc: UWB Radio Control descriptor | ||
207 | * @cmd_name: Name of the command being issued (for error messages) | ||
208 | * @cmd: Pointer to rccb structure containing the command; | ||
209 | * normally you embed this structure as the first member of | ||
210 | * the full command structure. | ||
211 | * @cmd_size: Size of the whole command buffer pointed to by @cmd. | ||
212 | * @reply: Pointer to the beginning of the confirmation event | ||
213 | * buffer. Normally bigger than an 'struct hwarc_rceb'. | ||
214 | * You need to fill out reply->bEventType and reply->wEvent (in | ||
215 | * cpu order) as the function will use them to verify the | ||
216 | * confirmation event. | ||
217 | * @reply_size: Size of the reply buffer | ||
218 | * | ||
219 | * The function checks that the length returned in the reply is at | ||
220 | * least as big as @reply_size; if not, it will be deemed an error and | ||
221 | * -EIO returned. | ||
222 | * | ||
223 | * @rc needs to be referenced | ||
224 | */ | ||
225 | ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name, | ||
226 | struct uwb_rccb *cmd, size_t cmd_size, | ||
227 | struct uwb_rceb *reply, size_t reply_size) | ||
228 | { | ||
229 | struct device *dev = &rc->uwb_dev.dev; | ||
230 | ssize_t result; | ||
231 | |||
232 | result = __uwb_rc_cmd(rc, cmd_name, | ||
233 | cmd, cmd_size, reply, reply_size, | ||
234 | reply->bEventType, reply->wEvent, NULL); | ||
235 | |||
236 | if (result > 0 && result < reply_size) { | ||
237 | dev_err(dev, "%s: not enough data returned for decoding reply " | ||
238 | "(%zu bytes received vs at least %zu needed)\n", | ||
239 | cmd_name, result, reply_size); | ||
240 | result = -EIO; | ||
241 | } | ||
242 | return result; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(uwb_rc_cmd); | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Generic function for issuing commands to the Radio Control | ||
249 | * Interface that return an unknown amount of data | ||
250 | * | ||
251 | * @rc: UWB Radio Control descriptor | ||
252 | * @cmd_name: Name of the command being issued (for error messages) | ||
253 | * @cmd: Pointer to rccb structure containing the command; | ||
254 | * normally you embed this structure as the first member of | ||
255 | * the full command structure. | ||
256 | * @cmd_size: Size of the whole command buffer pointed to by @cmd. | ||
257 | * @expected_type: Expected type in the return event | ||
258 | * @expected_event: Expected event code in the return event | ||
259 | * @preply: Here a pointer to where the event data is received will | ||
260 | * be stored. Once done with the data, free with kfree(). | ||
261 | * | ||
262 | * The function checks that the length returned in the reply is at | ||
263 | * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an | ||
264 | * error and -EIO returned. | ||
265 | * | ||
266 | * @rc needs to be referenced | ||
267 | */ | ||
268 | ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name, | ||
269 | struct uwb_rccb *cmd, size_t cmd_size, | ||
270 | u8 expected_type, u16 expected_event, | ||
271 | struct uwb_rceb **preply) | ||
272 | { | ||
273 | return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0, | ||
274 | expected_type, expected_event, preply); | ||
275 | } | ||
276 | EXPORT_SYMBOL_GPL(uwb_rc_vcmd); | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Reset a UWB Host Controller (and all radio settings) | ||
281 | * | ||
282 | * @rc: Host Controller descriptor | ||
283 | * @returns: 0 if ok, < 0 errno code on error | ||
284 | * | ||
285 | * We put the command on kmalloc'ed memory as some arches cannot do | ||
286 | * USB from the stack. The reply event is copied from an stage buffer, | ||
287 | * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. | ||
288 | */ | ||
289 | int uwb_rc_reset(struct uwb_rc *rc) | ||
290 | { | ||
291 | int result = -ENOMEM; | ||
292 | struct uwb_rc_evt_confirm reply; | ||
293 | struct uwb_rccb *cmd; | ||
294 | size_t cmd_size = sizeof(*cmd); | ||
295 | |||
296 | mutex_lock(&rc->uwb_dev.mutex); | ||
297 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
298 | if (cmd == NULL) | ||
299 | goto error_kzalloc; | ||
300 | cmd->bCommandType = UWB_RC_CET_GENERAL; | ||
301 | cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET); | ||
302 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
303 | reply.rceb.wEvent = UWB_RC_CMD_RESET; | ||
304 | result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size, | ||
305 | &reply.rceb, sizeof(reply)); | ||
306 | if (result < 0) | ||
307 | goto error_cmd; | ||
308 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
309 | dev_err(&rc->uwb_dev.dev, | ||
310 | "RESET: command execution failed: %s (%d)\n", | ||
311 | uwb_rc_strerror(reply.bResultCode), reply.bResultCode); | ||
312 | result = -EIO; | ||
313 | } | ||
314 | error_cmd: | ||
315 | kfree(cmd); | ||
316 | error_kzalloc: | ||
317 | mutex_unlock(&rc->uwb_dev.mutex); | ||
318 | return result; | ||
319 | } | ||
320 | |||
321 | int uwbd_msg_handle_reset(struct uwb_event *evt) | ||
322 | { | ||
323 | struct uwb_rc *rc = evt->rc; | ||
324 | int ret; | ||
325 | |||
326 | /* Need to prevent the RC hardware module going away while in | ||
327 | the rc->reset() call. */ | ||
328 | if (!try_module_get(rc->owner)) | ||
329 | return 0; | ||
330 | |||
331 | dev_info(&rc->uwb_dev.dev, "resetting radio controller\n"); | ||
332 | ret = rc->reset(rc); | ||
333 | if (ret) | ||
334 | dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret); | ||
335 | |||
336 | module_put(rc->owner); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * uwb_rc_reset_all - request a reset of the radio controller and PALs | ||
342 | * @rc: the radio controller of the hardware device to be reset. | ||
343 | * | ||
344 | * The full hardware reset of the radio controller and all the PALs | ||
345 | * will be scheduled. | ||
346 | */ | ||
347 | void uwb_rc_reset_all(struct uwb_rc *rc) | ||
348 | { | ||
349 | struct uwb_event *evt; | ||
350 | |||
351 | evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC); | ||
352 | if (unlikely(evt == NULL)) | ||
353 | return; | ||
354 | |||
355 | evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */ | ||
356 | evt->ts_jiffies = jiffies; | ||
357 | evt->type = UWB_EVT_TYPE_MSG; | ||
358 | evt->message = UWB_EVT_MSG_RESET; | ||
359 | |||
360 | uwbd_event_queue(evt); | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(uwb_rc_reset_all); | ||
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c new file mode 100644 index 000000000000..bae16204576d --- /dev/null +++ b/drivers/uwb/rsv.c | |||
@@ -0,0 +1,680 @@ | |||
1 | /* | ||
2 | * UWB reservation management. | ||
3 | * | ||
4 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/uwb.h> | ||
21 | |||
22 | #include "uwb-internal.h" | ||
23 | |||
24 | static void uwb_rsv_timer(unsigned long arg); | ||
25 | |||
26 | static const char *rsv_states[] = { | ||
27 | [UWB_RSV_STATE_NONE] = "none", | ||
28 | [UWB_RSV_STATE_O_INITIATED] = "initiated", | ||
29 | [UWB_RSV_STATE_O_PENDING] = "pending", | ||
30 | [UWB_RSV_STATE_O_MODIFIED] = "modified", | ||
31 | [UWB_RSV_STATE_O_ESTABLISHED] = "established", | ||
32 | [UWB_RSV_STATE_T_ACCEPTED] = "accepted", | ||
33 | [UWB_RSV_STATE_T_DENIED] = "denied", | ||
34 | [UWB_RSV_STATE_T_PENDING] = "pending", | ||
35 | }; | ||
36 | |||
37 | static const char *rsv_types[] = { | ||
38 | [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp", | ||
39 | [UWB_DRP_TYPE_HARD] = "hard", | ||
40 | [UWB_DRP_TYPE_SOFT] = "soft", | ||
41 | [UWB_DRP_TYPE_PRIVATE] = "private", | ||
42 | [UWB_DRP_TYPE_PCA] = "pca", | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * uwb_rsv_state_str - return a string for a reservation state | ||
47 | * @state: the reservation state. | ||
48 | */ | ||
49 | const char *uwb_rsv_state_str(enum uwb_rsv_state state) | ||
50 | { | ||
51 | if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST) | ||
52 | return "unknown"; | ||
53 | return rsv_states[state]; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(uwb_rsv_state_str); | ||
56 | |||
57 | /** | ||
58 | * uwb_rsv_type_str - return a string for a reservation type | ||
59 | * @type: the reservation type | ||
60 | */ | ||
61 | const char *uwb_rsv_type_str(enum uwb_drp_type type) | ||
62 | { | ||
63 | if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA) | ||
64 | return "invalid"; | ||
65 | return rsv_types[type]; | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(uwb_rsv_type_str); | ||
68 | |||
69 | static void uwb_rsv_dump(struct uwb_rsv *rsv) | ||
70 | { | ||
71 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
72 | struct uwb_dev_addr devaddr; | ||
73 | char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; | ||
74 | |||
75 | uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); | ||
76 | if (rsv->target.type == UWB_RSV_TARGET_DEV) | ||
77 | devaddr = rsv->target.dev->dev_addr; | ||
78 | else | ||
79 | devaddr = rsv->target.devaddr; | ||
80 | uwb_dev_addr_print(target, sizeof(target), &devaddr); | ||
81 | |||
82 | dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state)); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Get a free stream index for a reservation. | ||
87 | * | ||
88 | * If the target is a DevAddr (e.g., a WUSB cluster reservation) then | ||
89 | * the stream is allocated from a pool of per-RC stream indexes, | ||
90 | * otherwise a unique stream index for the target is selected. | ||
91 | */ | ||
92 | static int uwb_rsv_get_stream(struct uwb_rsv *rsv) | ||
93 | { | ||
94 | struct uwb_rc *rc = rsv->rc; | ||
95 | unsigned long *streams_bm; | ||
96 | int stream; | ||
97 | |||
98 | switch (rsv->target.type) { | ||
99 | case UWB_RSV_TARGET_DEV: | ||
100 | streams_bm = rsv->target.dev->streams; | ||
101 | break; | ||
102 | case UWB_RSV_TARGET_DEVADDR: | ||
103 | streams_bm = rc->uwb_dev.streams; | ||
104 | break; | ||
105 | default: | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS); | ||
110 | if (stream >= UWB_NUM_STREAMS) | ||
111 | return -EBUSY; | ||
112 | |||
113 | rsv->stream = stream; | ||
114 | set_bit(stream, streams_bm); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void uwb_rsv_put_stream(struct uwb_rsv *rsv) | ||
120 | { | ||
121 | struct uwb_rc *rc = rsv->rc; | ||
122 | unsigned long *streams_bm; | ||
123 | |||
124 | switch (rsv->target.type) { | ||
125 | case UWB_RSV_TARGET_DEV: | ||
126 | streams_bm = rsv->target.dev->streams; | ||
127 | break; | ||
128 | case UWB_RSV_TARGET_DEVADDR: | ||
129 | streams_bm = rc->uwb_dev.streams; | ||
130 | break; | ||
131 | default: | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | clear_bit(rsv->stream, streams_bm); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Generate a MAS allocation with a single row component. | ||
140 | */ | ||
141 | static void uwb_rsv_gen_alloc_row(struct uwb_mas_bm *mas, | ||
142 | int first_mas, int mas_per_zone, | ||
143 | int zs, int ze) | ||
144 | { | ||
145 | struct uwb_mas_bm col; | ||
146 | int z; | ||
147 | |||
148 | bitmap_zero(mas->bm, UWB_NUM_MAS); | ||
149 | bitmap_zero(col.bm, UWB_NUM_MAS); | ||
150 | bitmap_fill(col.bm, mas_per_zone); | ||
151 | bitmap_shift_left(col.bm, col.bm, first_mas + zs * UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
152 | |||
153 | for (z = zs; z <= ze; z++) { | ||
154 | bitmap_or(mas->bm, mas->bm, col.bm, UWB_NUM_MAS); | ||
155 | bitmap_shift_left(col.bm, col.bm, UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Allocate some MAS for this reservation based on current local | ||
161 | * availability, the reservation parameters (max_mas, min_mas, | ||
162 | * sparsity), and the WiMedia rules for MAS allocations. | ||
163 | * | ||
164 | * Returns -EBUSY is insufficient free MAS are available. | ||
165 | * | ||
166 | * FIXME: to simplify this, only safe reservations with a single row | ||
167 | * component in zones 1 to 15 are tried (zone 0 is skipped to avoid | ||
168 | * problems with the MAS reserved for the BP). | ||
169 | * | ||
170 | * [ECMA-368] section B.2. | ||
171 | */ | ||
172 | static int uwb_rsv_alloc_mas(struct uwb_rsv *rsv) | ||
173 | { | ||
174 | static const int safe_mas_in_row[UWB_NUM_ZONES] = { | ||
175 | 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, | ||
176 | }; | ||
177 | int n, r; | ||
178 | struct uwb_mas_bm mas; | ||
179 | bool found = false; | ||
180 | |||
181 | /* | ||
182 | * Search all valid safe allocations until either: too few MAS | ||
183 | * are available; or the smallest allocation with sufficient | ||
184 | * MAS is found. | ||
185 | * | ||
186 | * The top of the zones are preferred, so space for larger | ||
187 | * allocations is available in the bottom of the zone (e.g., a | ||
188 | * 15 MAS allocation should start in row 14 leaving space for | ||
189 | * a 120 MAS allocation at row 0). | ||
190 | */ | ||
191 | for (n = safe_mas_in_row[0]; n >= 1; n--) { | ||
192 | int num_mas; | ||
193 | |||
194 | num_mas = n * (UWB_NUM_ZONES - 1); | ||
195 | if (num_mas < rsv->min_mas) | ||
196 | break; | ||
197 | if (found && num_mas < rsv->max_mas) | ||
198 | break; | ||
199 | |||
200 | for (r = UWB_MAS_PER_ZONE-1; r >= 0; r--) { | ||
201 | if (safe_mas_in_row[r] < n) | ||
202 | continue; | ||
203 | uwb_rsv_gen_alloc_row(&mas, r, n, 1, UWB_NUM_ZONES); | ||
204 | if (uwb_drp_avail_reserve_pending(rsv->rc, &mas) == 0) { | ||
205 | found = true; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (!found) | ||
212 | return -EBUSY; | ||
213 | |||
214 | bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv) | ||
219 | { | ||
220 | int sframes = UWB_MAX_LOST_BEACONS; | ||
221 | |||
222 | /* | ||
223 | * Multicast reservations can become established within 1 | ||
224 | * super frame and should not be terminated if no response is | ||
225 | * received. | ||
226 | */ | ||
227 | if (rsv->is_multicast) { | ||
228 | if (rsv->state == UWB_RSV_STATE_O_INITIATED) | ||
229 | sframes = 1; | ||
230 | if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED) | ||
231 | sframes = 0; | ||
232 | } | ||
233 | |||
234 | rsv->expired = false; | ||
235 | if (sframes > 0) { | ||
236 | /* | ||
237 | * Add an additional 2 superframes to account for the | ||
238 | * time to send the SET DRP IE command. | ||
239 | */ | ||
240 | unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US; | ||
241 | mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us)); | ||
242 | } else | ||
243 | del_timer(&rsv->timer); | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Update a reservations state, and schedule an update of the | ||
248 | * transmitted DRP IEs. | ||
249 | */ | ||
250 | static void uwb_rsv_state_update(struct uwb_rsv *rsv, | ||
251 | enum uwb_rsv_state new_state) | ||
252 | { | ||
253 | rsv->state = new_state; | ||
254 | rsv->ie_valid = false; | ||
255 | |||
256 | uwb_rsv_dump(rsv); | ||
257 | |||
258 | uwb_rsv_stroke_timer(rsv); | ||
259 | uwb_rsv_sched_update(rsv->rc); | ||
260 | } | ||
261 | |||
262 | static void uwb_rsv_callback(struct uwb_rsv *rsv) | ||
263 | { | ||
264 | if (rsv->callback) | ||
265 | rsv->callback(rsv); | ||
266 | } | ||
267 | |||
268 | void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) | ||
269 | { | ||
270 | if (rsv->state == new_state) { | ||
271 | switch (rsv->state) { | ||
272 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
273 | case UWB_RSV_STATE_T_ACCEPTED: | ||
274 | case UWB_RSV_STATE_NONE: | ||
275 | uwb_rsv_stroke_timer(rsv); | ||
276 | break; | ||
277 | default: | ||
278 | /* Expecting a state transition so leave timer | ||
279 | as-is. */ | ||
280 | break; | ||
281 | } | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | switch (new_state) { | ||
286 | case UWB_RSV_STATE_NONE: | ||
287 | uwb_drp_avail_release(rsv->rc, &rsv->mas); | ||
288 | uwb_rsv_put_stream(rsv); | ||
289 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE); | ||
290 | uwb_rsv_callback(rsv); | ||
291 | break; | ||
292 | case UWB_RSV_STATE_O_INITIATED: | ||
293 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED); | ||
294 | break; | ||
295 | case UWB_RSV_STATE_O_PENDING: | ||
296 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING); | ||
297 | break; | ||
298 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
299 | uwb_drp_avail_reserve(rsv->rc, &rsv->mas); | ||
300 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
301 | uwb_rsv_callback(rsv); | ||
302 | break; | ||
303 | case UWB_RSV_STATE_T_ACCEPTED: | ||
304 | uwb_drp_avail_reserve(rsv->rc, &rsv->mas); | ||
305 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED); | ||
306 | uwb_rsv_callback(rsv); | ||
307 | break; | ||
308 | case UWB_RSV_STATE_T_DENIED: | ||
309 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED); | ||
310 | break; | ||
311 | default: | ||
312 | dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n", | ||
313 | uwb_rsv_state_str(new_state), new_state); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) | ||
318 | { | ||
319 | struct uwb_rsv *rsv; | ||
320 | |||
321 | rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL); | ||
322 | if (!rsv) | ||
323 | return NULL; | ||
324 | |||
325 | INIT_LIST_HEAD(&rsv->rc_node); | ||
326 | INIT_LIST_HEAD(&rsv->pal_node); | ||
327 | init_timer(&rsv->timer); | ||
328 | rsv->timer.function = uwb_rsv_timer; | ||
329 | rsv->timer.data = (unsigned long)rsv; | ||
330 | |||
331 | rsv->rc = rc; | ||
332 | |||
333 | return rsv; | ||
334 | } | ||
335 | |||
336 | static void uwb_rsv_free(struct uwb_rsv *rsv) | ||
337 | { | ||
338 | uwb_dev_put(rsv->owner); | ||
339 | if (rsv->target.type == UWB_RSV_TARGET_DEV) | ||
340 | uwb_dev_put(rsv->target.dev); | ||
341 | kfree(rsv); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * uwb_rsv_create - allocate and initialize a UWB reservation structure | ||
346 | * @rc: the radio controller | ||
347 | * @cb: callback to use when the reservation completes or terminates | ||
348 | * @pal_priv: data private to the PAL to be passed in the callback | ||
349 | * | ||
350 | * The callback is called when the state of the reservation changes from: | ||
351 | * | ||
352 | * - pending to accepted | ||
353 | * - pending to denined | ||
354 | * - accepted to terminated | ||
355 | * - pending to terminated | ||
356 | */ | ||
357 | struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv) | ||
358 | { | ||
359 | struct uwb_rsv *rsv; | ||
360 | |||
361 | rsv = uwb_rsv_alloc(rc); | ||
362 | if (!rsv) | ||
363 | return NULL; | ||
364 | |||
365 | rsv->callback = cb; | ||
366 | rsv->pal_priv = pal_priv; | ||
367 | |||
368 | return rsv; | ||
369 | } | ||
370 | EXPORT_SYMBOL_GPL(uwb_rsv_create); | ||
371 | |||
372 | void uwb_rsv_remove(struct uwb_rsv *rsv) | ||
373 | { | ||
374 | if (rsv->state != UWB_RSV_STATE_NONE) | ||
375 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
376 | del_timer_sync(&rsv->timer); | ||
377 | list_del(&rsv->rc_node); | ||
378 | uwb_rsv_free(rsv); | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * uwb_rsv_destroy - free a UWB reservation structure | ||
383 | * @rsv: the reservation to free | ||
384 | * | ||
385 | * The reservation will be terminated if it is pending or established. | ||
386 | */ | ||
387 | void uwb_rsv_destroy(struct uwb_rsv *rsv) | ||
388 | { | ||
389 | struct uwb_rc *rc = rsv->rc; | ||
390 | |||
391 | mutex_lock(&rc->rsvs_mutex); | ||
392 | uwb_rsv_remove(rsv); | ||
393 | mutex_unlock(&rc->rsvs_mutex); | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(uwb_rsv_destroy); | ||
396 | |||
397 | /** | ||
398 | * usb_rsv_establish - start a reservation establishment | ||
399 | * @rsv: the reservation | ||
400 | * | ||
401 | * The PAL should fill in @rsv's owner, target, type, max_mas, | ||
402 | * min_mas, sparsity and is_multicast fields. If the target is a | ||
403 | * uwb_dev it must be referenced. | ||
404 | * | ||
405 | * The reservation's callback will be called when the reservation is | ||
406 | * accepted, denied or times out. | ||
407 | */ | ||
408 | int uwb_rsv_establish(struct uwb_rsv *rsv) | ||
409 | { | ||
410 | struct uwb_rc *rc = rsv->rc; | ||
411 | int ret; | ||
412 | |||
413 | mutex_lock(&rc->rsvs_mutex); | ||
414 | |||
415 | ret = uwb_rsv_get_stream(rsv); | ||
416 | if (ret) | ||
417 | goto out; | ||
418 | |||
419 | ret = uwb_rsv_alloc_mas(rsv); | ||
420 | if (ret) { | ||
421 | uwb_rsv_put_stream(rsv); | ||
422 | goto out; | ||
423 | } | ||
424 | |||
425 | list_add_tail(&rsv->rc_node, &rc->reservations); | ||
426 | rsv->owner = &rc->uwb_dev; | ||
427 | uwb_dev_get(rsv->owner); | ||
428 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED); | ||
429 | out: | ||
430 | mutex_unlock(&rc->rsvs_mutex); | ||
431 | return ret; | ||
432 | } | ||
433 | EXPORT_SYMBOL_GPL(uwb_rsv_establish); | ||
434 | |||
435 | /** | ||
436 | * uwb_rsv_modify - modify an already established reservation | ||
437 | * @rsv: the reservation to modify | ||
438 | * @max_mas: new maximum MAS to reserve | ||
439 | * @min_mas: new minimum MAS to reserve | ||
440 | * @sparsity: new sparsity to use | ||
441 | * | ||
442 | * FIXME: implement this once there are PALs that use it. | ||
443 | */ | ||
444 | int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity) | ||
445 | { | ||
446 | return -ENOSYS; | ||
447 | } | ||
448 | EXPORT_SYMBOL_GPL(uwb_rsv_modify); | ||
449 | |||
450 | /** | ||
451 | * uwb_rsv_terminate - terminate an established reservation | ||
452 | * @rsv: the reservation to terminate | ||
453 | * | ||
454 | * A reservation is terminated by removing the DRP IE from the beacon, | ||
455 | * the other end will consider the reservation to be terminated when | ||
456 | * it does not see the DRP IE for at least mMaxLostBeacons. | ||
457 | * | ||
458 | * If applicable, the reference to the target uwb_dev will be released. | ||
459 | */ | ||
460 | void uwb_rsv_terminate(struct uwb_rsv *rsv) | ||
461 | { | ||
462 | struct uwb_rc *rc = rsv->rc; | ||
463 | |||
464 | mutex_lock(&rc->rsvs_mutex); | ||
465 | |||
466 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
467 | |||
468 | mutex_unlock(&rc->rsvs_mutex); | ||
469 | } | ||
470 | EXPORT_SYMBOL_GPL(uwb_rsv_terminate); | ||
471 | |||
472 | /** | ||
473 | * uwb_rsv_accept - accept a new reservation from a peer | ||
474 | * @rsv: the reservation | ||
475 | * @cb: call back for reservation changes | ||
476 | * @pal_priv: data to be passed in the above call back | ||
477 | * | ||
478 | * Reservation requests from peers are denied unless a PAL accepts it | ||
479 | * by calling this function. | ||
480 | */ | ||
481 | void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv) | ||
482 | { | ||
483 | rsv->callback = cb; | ||
484 | rsv->pal_priv = pal_priv; | ||
485 | rsv->state = UWB_RSV_STATE_T_ACCEPTED; | ||
486 | } | ||
487 | EXPORT_SYMBOL_GPL(uwb_rsv_accept); | ||
488 | |||
489 | /* | ||
490 | * Is a received DRP IE for this reservation? | ||
491 | */ | ||
492 | static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src, | ||
493 | struct uwb_ie_drp *drp_ie) | ||
494 | { | ||
495 | struct uwb_dev_addr *rsv_src; | ||
496 | int stream; | ||
497 | |||
498 | stream = uwb_ie_drp_stream_index(drp_ie); | ||
499 | |||
500 | if (rsv->stream != stream) | ||
501 | return false; | ||
502 | |||
503 | switch (rsv->target.type) { | ||
504 | case UWB_RSV_TARGET_DEVADDR: | ||
505 | return rsv->stream == stream; | ||
506 | case UWB_RSV_TARGET_DEV: | ||
507 | if (uwb_ie_drp_owner(drp_ie)) | ||
508 | rsv_src = &rsv->owner->dev_addr; | ||
509 | else | ||
510 | rsv_src = &rsv->target.dev->dev_addr; | ||
511 | return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0; | ||
512 | } | ||
513 | return false; | ||
514 | } | ||
515 | |||
516 | static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, | ||
517 | struct uwb_dev *src, | ||
518 | struct uwb_ie_drp *drp_ie) | ||
519 | { | ||
520 | struct uwb_rsv *rsv; | ||
521 | struct uwb_pal *pal; | ||
522 | enum uwb_rsv_state state; | ||
523 | |||
524 | rsv = uwb_rsv_alloc(rc); | ||
525 | if (!rsv) | ||
526 | return NULL; | ||
527 | |||
528 | rsv->rc = rc; | ||
529 | rsv->owner = src; | ||
530 | uwb_dev_get(rsv->owner); | ||
531 | rsv->target.type = UWB_RSV_TARGET_DEV; | ||
532 | rsv->target.dev = &rc->uwb_dev; | ||
533 | rsv->type = uwb_ie_drp_type(drp_ie); | ||
534 | rsv->stream = uwb_ie_drp_stream_index(drp_ie); | ||
535 | set_bit(rsv->stream, rsv->owner->streams); | ||
536 | uwb_drp_ie_to_bm(&rsv->mas, drp_ie); | ||
537 | |||
538 | /* | ||
539 | * See if any PALs are interested in this reservation. If not, | ||
540 | * deny the request. | ||
541 | */ | ||
542 | rsv->state = UWB_RSV_STATE_T_DENIED; | ||
543 | spin_lock(&rc->pal_lock); | ||
544 | list_for_each_entry(pal, &rc->pals, node) { | ||
545 | if (pal->new_rsv) | ||
546 | pal->new_rsv(rsv); | ||
547 | if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) | ||
548 | break; | ||
549 | } | ||
550 | spin_unlock(&rc->pal_lock); | ||
551 | |||
552 | list_add_tail(&rsv->rc_node, &rc->reservations); | ||
553 | state = rsv->state; | ||
554 | rsv->state = UWB_RSV_STATE_NONE; | ||
555 | uwb_rsv_set_state(rsv, state); | ||
556 | |||
557 | return rsv; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * uwb_rsv_find - find a reservation for a received DRP IE. | ||
562 | * @rc: the radio controller | ||
563 | * @src: source of the DRP IE | ||
564 | * @drp_ie: the DRP IE | ||
565 | * | ||
566 | * If the reservation cannot be found and the DRP IE is from a peer | ||
567 | * attempting to establish a new reservation, create a new reservation | ||
568 | * and add it to the list. | ||
569 | */ | ||
570 | struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, | ||
571 | struct uwb_ie_drp *drp_ie) | ||
572 | { | ||
573 | struct uwb_rsv *rsv; | ||
574 | |||
575 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
576 | if (uwb_rsv_match(rsv, src, drp_ie)) | ||
577 | return rsv; | ||
578 | } | ||
579 | |||
580 | if (uwb_ie_drp_owner(drp_ie)) | ||
581 | return uwb_rsv_new_target(rc, src, drp_ie); | ||
582 | |||
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * Go through all the reservations and check for timeouts and (if | ||
588 | * necessary) update their DRP IEs. | ||
589 | * | ||
590 | * FIXME: look at building the SET_DRP_IE command here rather than | ||
591 | * having to rescan the list in uwb_rc_send_all_drp_ie(). | ||
592 | */ | ||
593 | static bool uwb_rsv_update_all(struct uwb_rc *rc) | ||
594 | { | ||
595 | struct uwb_rsv *rsv, *t; | ||
596 | bool ie_updated = false; | ||
597 | |||
598 | list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { | ||
599 | if (rsv->expired) | ||
600 | uwb_drp_handle_timeout(rsv); | ||
601 | if (!rsv->ie_valid) { | ||
602 | uwb_drp_ie_update(rsv); | ||
603 | ie_updated = true; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | return ie_updated; | ||
608 | } | ||
609 | |||
610 | void uwb_rsv_sched_update(struct uwb_rc *rc) | ||
611 | { | ||
612 | queue_work(rc->rsv_workq, &rc->rsv_update_work); | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * Update DRP IEs and, if necessary, the DRP Availability IE and send | ||
617 | * the updated IEs to the radio controller. | ||
618 | */ | ||
619 | static void uwb_rsv_update_work(struct work_struct *work) | ||
620 | { | ||
621 | struct uwb_rc *rc = container_of(work, struct uwb_rc, rsv_update_work); | ||
622 | bool ie_updated; | ||
623 | |||
624 | mutex_lock(&rc->rsvs_mutex); | ||
625 | |||
626 | ie_updated = uwb_rsv_update_all(rc); | ||
627 | |||
628 | if (!rc->drp_avail.ie_valid) { | ||
629 | uwb_drp_avail_ie_update(rc); | ||
630 | ie_updated = true; | ||
631 | } | ||
632 | |||
633 | if (ie_updated) | ||
634 | uwb_rc_send_all_drp_ie(rc); | ||
635 | |||
636 | mutex_unlock(&rc->rsvs_mutex); | ||
637 | } | ||
638 | |||
639 | static void uwb_rsv_timer(unsigned long arg) | ||
640 | { | ||
641 | struct uwb_rsv *rsv = (struct uwb_rsv *)arg; | ||
642 | |||
643 | rsv->expired = true; | ||
644 | uwb_rsv_sched_update(rsv->rc); | ||
645 | } | ||
646 | |||
647 | void uwb_rsv_init(struct uwb_rc *rc) | ||
648 | { | ||
649 | INIT_LIST_HEAD(&rc->reservations); | ||
650 | mutex_init(&rc->rsvs_mutex); | ||
651 | INIT_WORK(&rc->rsv_update_work, uwb_rsv_update_work); | ||
652 | |||
653 | bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS); | ||
654 | } | ||
655 | |||
656 | int uwb_rsv_setup(struct uwb_rc *rc) | ||
657 | { | ||
658 | char name[16]; | ||
659 | |||
660 | snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev)); | ||
661 | rc->rsv_workq = create_singlethread_workqueue(name); | ||
662 | if (rc->rsv_workq == NULL) | ||
663 | return -ENOMEM; | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | void uwb_rsv_cleanup(struct uwb_rc *rc) | ||
669 | { | ||
670 | struct uwb_rsv *rsv, *t; | ||
671 | |||
672 | mutex_lock(&rc->rsvs_mutex); | ||
673 | list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { | ||
674 | uwb_rsv_remove(rsv); | ||
675 | } | ||
676 | mutex_unlock(&rc->rsvs_mutex); | ||
677 | |||
678 | cancel_work_sync(&rc->rsv_update_work); | ||
679 | destroy_workqueue(rc->rsv_workq); | ||
680 | } | ||
diff --git a/drivers/uwb/scan.c b/drivers/uwb/scan.c new file mode 100644 index 000000000000..2d270748f32b --- /dev/null +++ b/drivers/uwb/scan.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Scanning management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * | ||
24 | * FIXME: docs | ||
25 | * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal | ||
26 | * with each other. Currently seems that START_BEACON while | ||
27 | * SCAN_ONLY will cancel the scan, so we need to update the | ||
28 | * state here. Clarification request sent by email on | ||
29 | * 10/05/2005. | ||
30 | * 10/28/2005 No clear answer heard--maybe we'll hack the API | ||
31 | * so that when we start beaconing, if the HC is | ||
32 | * scanning in a mode not compatible with beaconing | ||
33 | * we just fail. | ||
34 | */ | ||
35 | |||
36 | #include <linux/device.h> | ||
37 | #include <linux/err.h> | ||
38 | #include "uwb-internal.h" | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Start/stop scanning in a radio controller | ||
43 | * | ||
44 | * @rc: UWB Radio Controlller | ||
45 | * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12] | ||
46 | * @type: Type of scanning to do. | ||
47 | * @bpst_offset: value at which to start scanning (if type == | ||
48 | * UWB_SCAN_ONLY_STARTTIME) | ||
49 | * @returns: 0 if ok, < 0 errno code on error | ||
50 | * | ||
51 | * We put the command on kmalloc'ed memory as some arches cannot do | ||
52 | * USB from the stack. The reply event is copied from an stage buffer, | ||
53 | * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. | ||
54 | */ | ||
55 | int uwb_rc_scan(struct uwb_rc *rc, | ||
56 | unsigned channel, enum uwb_scan_type type, | ||
57 | unsigned bpst_offset) | ||
58 | { | ||
59 | int result; | ||
60 | struct uwb_rc_cmd_scan *cmd; | ||
61 | struct uwb_rc_evt_confirm reply; | ||
62 | |||
63 | result = -ENOMEM; | ||
64 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
65 | if (cmd == NULL) | ||
66 | goto error_kzalloc; | ||
67 | mutex_lock(&rc->uwb_dev.mutex); | ||
68 | cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
69 | cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN); | ||
70 | cmd->bChannelNumber = channel; | ||
71 | cmd->bScanState = type; | ||
72 | cmd->wStartTime = cpu_to_le16(bpst_offset); | ||
73 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
74 | reply.rceb.wEvent = UWB_RC_CMD_SCAN; | ||
75 | result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd), | ||
76 | &reply.rceb, sizeof(reply)); | ||
77 | if (result < 0) | ||
78 | goto error_cmd; | ||
79 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
80 | dev_err(&rc->uwb_dev.dev, | ||
81 | "SCAN: command execution failed: %s (%d)\n", | ||
82 | uwb_rc_strerror(reply.bResultCode), reply.bResultCode); | ||
83 | result = -EIO; | ||
84 | goto error_cmd; | ||
85 | } | ||
86 | rc->scanning = channel; | ||
87 | rc->scan_type = type; | ||
88 | error_cmd: | ||
89 | mutex_unlock(&rc->uwb_dev.mutex); | ||
90 | kfree(cmd); | ||
91 | error_kzalloc: | ||
92 | return result; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Print scanning state | ||
97 | */ | ||
98 | static ssize_t uwb_rc_scan_show(struct device *dev, | ||
99 | struct device_attribute *attr, char *buf) | ||
100 | { | ||
101 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
102 | struct uwb_rc *rc = uwb_dev->rc; | ||
103 | ssize_t result; | ||
104 | |||
105 | mutex_lock(&rc->uwb_dev.mutex); | ||
106 | result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type); | ||
107 | mutex_unlock(&rc->uwb_dev.mutex); | ||
108 | return result; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * | ||
113 | */ | ||
114 | static ssize_t uwb_rc_scan_store(struct device *dev, | ||
115 | struct device_attribute *attr, | ||
116 | const char *buf, size_t size) | ||
117 | { | ||
118 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
119 | struct uwb_rc *rc = uwb_dev->rc; | ||
120 | unsigned channel; | ||
121 | unsigned type; | ||
122 | unsigned bpst_offset = 0; | ||
123 | ssize_t result = -EINVAL; | ||
124 | |||
125 | result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset); | ||
126 | if (result >= 2 && type < UWB_SCAN_TOP) | ||
127 | result = uwb_rc_scan(rc, channel, type, bpst_offset); | ||
128 | |||
129 | return result < 0 ? result : size; | ||
130 | } | ||
131 | |||
132 | /** Radio Control sysfs interface (declaration) */ | ||
133 | DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store); | ||
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c new file mode 100644 index 000000000000..2d8d62d9f53e --- /dev/null +++ b/drivers/uwb/umc-bus.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * Bus for UWB Multi-interface Controller capabilities. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This file is released under the GNU GPL v2. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sysfs.h> | ||
10 | #include <linux/workqueue.h> | ||
11 | #include <linux/uwb/umc.h> | ||
12 | #include <linux/pci.h> | ||
13 | |||
14 | static int umc_bus_unbind_helper(struct device *dev, void *data) | ||
15 | { | ||
16 | struct device *parent = data; | ||
17 | |||
18 | if (dev->parent == parent && dev->driver) | ||
19 | device_release_driver(dev); | ||
20 | return 0; | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * umc_controller_reset - reset the whole UMC controller | ||
25 | * @umc: the UMC device for the radio controller. | ||
26 | * | ||
27 | * Drivers will be unbound from all UMC devices belonging to the | ||
28 | * controller and then the radio controller will be rebound. The | ||
29 | * radio controller is expected to do a full hardware reset when it is | ||
30 | * probed. | ||
31 | * | ||
32 | * If this is called while a probe() or remove() is in progress it | ||
33 | * will return -EAGAIN and not perform the reset. | ||
34 | */ | ||
35 | int umc_controller_reset(struct umc_dev *umc) | ||
36 | { | ||
37 | struct device *parent = umc->dev.parent; | ||
38 | int ret; | ||
39 | |||
40 | if (down_trylock(&parent->sem)) | ||
41 | return -EAGAIN; | ||
42 | bus_for_each_dev(&umc_bus_type, NULL, parent, umc_bus_unbind_helper); | ||
43 | ret = device_attach(&umc->dev); | ||
44 | if (ret == 1) | ||
45 | ret = 0; | ||
46 | up(&parent->sem); | ||
47 | |||
48 | return ret; | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(umc_controller_reset); | ||
51 | |||
52 | /** | ||
53 | * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device. | ||
54 | * @umc_drv: umc driver with match_data pointing to a zero-terminated | ||
55 | * table of pci_device_id's. | ||
56 | * @umc: umc device whose parent is to be matched. | ||
57 | */ | ||
58 | int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc) | ||
59 | { | ||
60 | const struct pci_device_id *id_table = umc_drv->match_data; | ||
61 | struct pci_dev *pci; | ||
62 | |||
63 | if (umc->dev.parent->bus != &pci_bus_type) | ||
64 | return 0; | ||
65 | |||
66 | pci = to_pci_dev(umc->dev.parent); | ||
67 | return pci_match_id(id_table, pci) != NULL; | ||
68 | } | ||
69 | EXPORT_SYMBOL_GPL(umc_match_pci_id); | ||
70 | |||
71 | static int umc_bus_rescan_helper(struct device *dev, void *data) | ||
72 | { | ||
73 | int ret = 0; | ||
74 | |||
75 | if (!dev->driver) | ||
76 | ret = device_attach(dev); | ||
77 | |||
78 | return ret < 0 ? ret : 0; | ||
79 | } | ||
80 | |||
81 | static void umc_bus_rescan(void) | ||
82 | { | ||
83 | int err; | ||
84 | |||
85 | /* | ||
86 | * We can't use bus_rescan_devices() here as it deadlocks when | ||
87 | * it tries to retake the dev->parent semaphore. | ||
88 | */ | ||
89 | err = bus_for_each_dev(&umc_bus_type, NULL, NULL, umc_bus_rescan_helper); | ||
90 | if (err < 0) | ||
91 | printk(KERN_WARNING "%s: rescan of bus failed: %d\n", | ||
92 | KBUILD_MODNAME, err); | ||
93 | } | ||
94 | |||
95 | static int umc_bus_match(struct device *dev, struct device_driver *drv) | ||
96 | { | ||
97 | struct umc_dev *umc = to_umc_dev(dev); | ||
98 | struct umc_driver *umc_driver = to_umc_driver(drv); | ||
99 | |||
100 | if (umc->cap_id == umc_driver->cap_id) { | ||
101 | if (umc_driver->match) | ||
102 | return umc_driver->match(umc_driver, umc); | ||
103 | else | ||
104 | return 1; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int umc_device_probe(struct device *dev) | ||
110 | { | ||
111 | struct umc_dev *umc; | ||
112 | struct umc_driver *umc_driver; | ||
113 | int err; | ||
114 | |||
115 | umc_driver = to_umc_driver(dev->driver); | ||
116 | umc = to_umc_dev(dev); | ||
117 | |||
118 | get_device(dev); | ||
119 | err = umc_driver->probe(umc); | ||
120 | if (err) | ||
121 | put_device(dev); | ||
122 | else | ||
123 | umc_bus_rescan(); | ||
124 | |||
125 | return err; | ||
126 | } | ||
127 | |||
128 | static int umc_device_remove(struct device *dev) | ||
129 | { | ||
130 | struct umc_dev *umc; | ||
131 | struct umc_driver *umc_driver; | ||
132 | |||
133 | umc_driver = to_umc_driver(dev->driver); | ||
134 | umc = to_umc_dev(dev); | ||
135 | |||
136 | umc_driver->remove(umc); | ||
137 | put_device(dev); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int umc_device_suspend(struct device *dev, pm_message_t state) | ||
142 | { | ||
143 | struct umc_dev *umc; | ||
144 | struct umc_driver *umc_driver; | ||
145 | int err = 0; | ||
146 | |||
147 | umc = to_umc_dev(dev); | ||
148 | |||
149 | if (dev->driver) { | ||
150 | umc_driver = to_umc_driver(dev->driver); | ||
151 | if (umc_driver->suspend) | ||
152 | err = umc_driver->suspend(umc, state); | ||
153 | } | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | static int umc_device_resume(struct device *dev) | ||
158 | { | ||
159 | struct umc_dev *umc; | ||
160 | struct umc_driver *umc_driver; | ||
161 | int err = 0; | ||
162 | |||
163 | umc = to_umc_dev(dev); | ||
164 | |||
165 | if (dev->driver) { | ||
166 | umc_driver = to_umc_driver(dev->driver); | ||
167 | if (umc_driver->resume) | ||
168 | err = umc_driver->resume(umc); | ||
169 | } | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
174 | { | ||
175 | struct umc_dev *umc = to_umc_dev(dev); | ||
176 | |||
177 | return sprintf(buf, "0x%02x\n", umc->cap_id); | ||
178 | } | ||
179 | |||
180 | static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
181 | { | ||
182 | struct umc_dev *umc = to_umc_dev(dev); | ||
183 | |||
184 | return sprintf(buf, "0x%04x\n", umc->version); | ||
185 | } | ||
186 | |||
187 | static struct device_attribute umc_dev_attrs[] = { | ||
188 | __ATTR_RO(capability_id), | ||
189 | __ATTR_RO(version), | ||
190 | __ATTR_NULL, | ||
191 | }; | ||
192 | |||
193 | struct bus_type umc_bus_type = { | ||
194 | .name = "umc", | ||
195 | .match = umc_bus_match, | ||
196 | .probe = umc_device_probe, | ||
197 | .remove = umc_device_remove, | ||
198 | .suspend = umc_device_suspend, | ||
199 | .resume = umc_device_resume, | ||
200 | .dev_attrs = umc_dev_attrs, | ||
201 | }; | ||
202 | EXPORT_SYMBOL_GPL(umc_bus_type); | ||
203 | |||
204 | static int __init umc_bus_init(void) | ||
205 | { | ||
206 | return bus_register(&umc_bus_type); | ||
207 | } | ||
208 | module_init(umc_bus_init); | ||
209 | |||
210 | static void __exit umc_bus_exit(void) | ||
211 | { | ||
212 | bus_unregister(&umc_bus_type); | ||
213 | } | ||
214 | module_exit(umc_bus_exit); | ||
215 | |||
216 | MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus"); | ||
217 | MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); | ||
218 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c new file mode 100644 index 000000000000..aa44e1c1a102 --- /dev/null +++ b/drivers/uwb/umc-dev.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * UWB Multi-interface Controller device management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This file is released under the GNU GPL v2. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/uwb/umc.h> | ||
10 | #define D_LOCAL 0 | ||
11 | #include <linux/uwb/debug.h> | ||
12 | |||
13 | static void umc_device_release(struct device *dev) | ||
14 | { | ||
15 | struct umc_dev *umc = to_umc_dev(dev); | ||
16 | |||
17 | kfree(umc); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * umc_device_create - allocate a child UMC device | ||
22 | * @parent: parent of the new UMC device. | ||
23 | * @n: index of the new device. | ||
24 | * | ||
25 | * The new UMC device will have a bus ID of the parent with '-n' | ||
26 | * appended. | ||
27 | */ | ||
28 | struct umc_dev *umc_device_create(struct device *parent, int n) | ||
29 | { | ||
30 | struct umc_dev *umc; | ||
31 | |||
32 | umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL); | ||
33 | if (umc) { | ||
34 | snprintf(umc->dev.bus_id, sizeof(umc->dev.bus_id), "%s-%d", | ||
35 | parent->bus_id, n); | ||
36 | umc->dev.parent = parent; | ||
37 | umc->dev.bus = &umc_bus_type; | ||
38 | umc->dev.release = umc_device_release; | ||
39 | |||
40 | umc->dev.dma_mask = parent->dma_mask; | ||
41 | } | ||
42 | return umc; | ||
43 | } | ||
44 | EXPORT_SYMBOL_GPL(umc_device_create); | ||
45 | |||
46 | /** | ||
47 | * umc_device_register - register a UMC device | ||
48 | * @umc: pointer to the UMC device | ||
49 | * | ||
50 | * The memory resource for the UMC device is acquired and the device | ||
51 | * registered with the system. | ||
52 | */ | ||
53 | int umc_device_register(struct umc_dev *umc) | ||
54 | { | ||
55 | int err; | ||
56 | |||
57 | d_fnstart(3, &umc->dev, "(umc_dev %p)\n", umc); | ||
58 | |||
59 | err = request_resource(umc->resource.parent, &umc->resource); | ||
60 | if (err < 0) { | ||
61 | dev_err(&umc->dev, "can't allocate resource range " | ||
62 | "%016Lx to %016Lx: %d\n", | ||
63 | (unsigned long long)umc->resource.start, | ||
64 | (unsigned long long)umc->resource.end, | ||
65 | err); | ||
66 | goto error_request_resource; | ||
67 | } | ||
68 | |||
69 | err = device_register(&umc->dev); | ||
70 | if (err < 0) | ||
71 | goto error_device_register; | ||
72 | d_fnend(3, &umc->dev, "(umc_dev %p) = 0\n", umc); | ||
73 | return 0; | ||
74 | |||
75 | error_device_register: | ||
76 | release_resource(&umc->resource); | ||
77 | error_request_resource: | ||
78 | d_fnend(3, &umc->dev, "(umc_dev %p) = %d\n", umc, err); | ||
79 | return err; | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(umc_device_register); | ||
82 | |||
83 | /** | ||
84 | * umc_device_unregister - unregister a UMC device | ||
85 | * @umc: pointer to the UMC device | ||
86 | * | ||
87 | * First we unregister the device, make sure the driver can do it's | ||
88 | * resource release thing and then we try to release any left over | ||
89 | * resources. We take a ref to the device, to make sure it doesn't | ||
90 | * dissapear under our feet. | ||
91 | */ | ||
92 | void umc_device_unregister(struct umc_dev *umc) | ||
93 | { | ||
94 | struct device *dev; | ||
95 | if (!umc) | ||
96 | return; | ||
97 | dev = get_device(&umc->dev); | ||
98 | d_fnstart(3, dev, "(umc_dev %p)\n", umc); | ||
99 | device_unregister(&umc->dev); | ||
100 | release_resource(&umc->resource); | ||
101 | d_fnend(3, dev, "(umc_dev %p) = void\n", umc); | ||
102 | put_device(dev); | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(umc_device_unregister); | ||
diff --git a/drivers/uwb/umc-drv.c b/drivers/uwb/umc-drv.c new file mode 100644 index 000000000000..367b5eb85d60 --- /dev/null +++ b/drivers/uwb/umc-drv.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * UWB Multi-interface Controller driver management. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This file is released under the GNU GPL v2. | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/uwb/umc.h> | ||
10 | |||
11 | int __umc_driver_register(struct umc_driver *umc_drv, struct module *module, | ||
12 | const char *mod_name) | ||
13 | { | ||
14 | umc_drv->driver.name = umc_drv->name; | ||
15 | umc_drv->driver.owner = module; | ||
16 | umc_drv->driver.mod_name = mod_name; | ||
17 | umc_drv->driver.bus = &umc_bus_type; | ||
18 | |||
19 | return driver_register(&umc_drv->driver); | ||
20 | } | ||
21 | EXPORT_SYMBOL_GPL(__umc_driver_register); | ||
22 | |||
23 | /** | ||
24 | * umc_driver_register - unregister a UMC capabiltity driver. | ||
25 | * @umc_drv: pointer to the driver. | ||
26 | */ | ||
27 | void umc_driver_unregister(struct umc_driver *umc_drv) | ||
28 | { | ||
29 | driver_unregister(&umc_drv->driver); | ||
30 | } | ||
31 | EXPORT_SYMBOL_GPL(umc_driver_unregister); | ||
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c new file mode 100644 index 000000000000..6d232c35d07d --- /dev/null +++ b/drivers/uwb/uwb-debug.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Debug support | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: doc | ||
24 | */ | ||
25 | |||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/notifier.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/debugfs.h> | ||
32 | #include <linux/uaccess.h> | ||
33 | #include <linux/seq_file.h> | ||
34 | |||
35 | #include <linux/uwb/debug-cmd.h> | ||
36 | #define D_LOCAL 0 | ||
37 | #include <linux/uwb/debug.h> | ||
38 | |||
39 | #include "uwb-internal.h" | ||
40 | |||
41 | void dump_bytes(struct device *dev, const void *_buf, size_t rsize) | ||
42 | { | ||
43 | const char *buf = _buf; | ||
44 | char line[32]; | ||
45 | size_t offset = 0; | ||
46 | int cnt, cnt2; | ||
47 | for (cnt = 0; cnt < rsize; cnt += 8) { | ||
48 | size_t rtop = rsize - cnt < 8 ? rsize - cnt : 8; | ||
49 | for (offset = cnt2 = 0; cnt2 < rtop; cnt2++) { | ||
50 | offset += scnprintf(line + offset, sizeof(line) - offset, | ||
51 | "%02x ", buf[cnt + cnt2] & 0xff); | ||
52 | } | ||
53 | if (dev) | ||
54 | dev_info(dev, "%s\n", line); | ||
55 | else | ||
56 | printk(KERN_INFO "%s\n", line); | ||
57 | } | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(dump_bytes); | ||
60 | |||
61 | /* | ||
62 | * Debug interface | ||
63 | * | ||
64 | * Per radio controller debugfs files (in uwb/uwbN/): | ||
65 | * | ||
66 | * command: Flexible command interface (see <linux/uwb/debug-cmd.h>). | ||
67 | * | ||
68 | * reservations: information on reservations. | ||
69 | * | ||
70 | * accept: Set to true (Y or 1) to accept reservation requests from | ||
71 | * peers. | ||
72 | * | ||
73 | * drp_avail: DRP availability information. | ||
74 | */ | ||
75 | |||
76 | struct uwb_dbg { | ||
77 | struct uwb_pal pal; | ||
78 | |||
79 | u32 accept; | ||
80 | struct list_head rsvs; | ||
81 | |||
82 | struct dentry *root_d; | ||
83 | struct dentry *command_f; | ||
84 | struct dentry *reservations_f; | ||
85 | struct dentry *accept_f; | ||
86 | struct dentry *drp_avail_f; | ||
87 | }; | ||
88 | |||
89 | static struct dentry *root_dir; | ||
90 | |||
91 | static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv) | ||
92 | { | ||
93 | struct uwb_rc *rc = rsv->rc; | ||
94 | struct device *dev = &rc->uwb_dev.dev; | ||
95 | struct uwb_dev_addr devaddr; | ||
96 | char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; | ||
97 | |||
98 | uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); | ||
99 | if (rsv->target.type == UWB_RSV_TARGET_DEV) | ||
100 | devaddr = rsv->target.dev->dev_addr; | ||
101 | else | ||
102 | devaddr = rsv->target.devaddr; | ||
103 | uwb_dev_addr_print(target, sizeof(target), &devaddr); | ||
104 | |||
105 | dev_dbg(dev, "debug: rsv %s -> %s: %s\n", | ||
106 | owner, target, uwb_rsv_state_str(rsv->state)); | ||
107 | } | ||
108 | |||
109 | static int cmd_rsv_establish(struct uwb_rc *rc, | ||
110 | struct uwb_dbg_cmd_rsv_establish *cmd) | ||
111 | { | ||
112 | struct uwb_mac_addr macaddr; | ||
113 | struct uwb_rsv *rsv; | ||
114 | struct uwb_dev *target; | ||
115 | int ret; | ||
116 | |||
117 | memcpy(&macaddr, cmd->target, sizeof(macaddr)); | ||
118 | target = uwb_dev_get_by_macaddr(rc, &macaddr); | ||
119 | if (target == NULL) | ||
120 | return -ENODEV; | ||
121 | |||
122 | rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, NULL); | ||
123 | if (rsv == NULL) { | ||
124 | uwb_dev_put(target); | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | |||
128 | rsv->owner = &rc->uwb_dev; | ||
129 | rsv->target.type = UWB_RSV_TARGET_DEV; | ||
130 | rsv->target.dev = target; | ||
131 | rsv->type = cmd->type; | ||
132 | rsv->max_mas = cmd->max_mas; | ||
133 | rsv->min_mas = cmd->min_mas; | ||
134 | rsv->sparsity = cmd->sparsity; | ||
135 | |||
136 | ret = uwb_rsv_establish(rsv); | ||
137 | if (ret) | ||
138 | uwb_rsv_destroy(rsv); | ||
139 | else | ||
140 | list_add_tail(&rsv->pal_node, &rc->dbg->rsvs); | ||
141 | |||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static int cmd_rsv_terminate(struct uwb_rc *rc, | ||
146 | struct uwb_dbg_cmd_rsv_terminate *cmd) | ||
147 | { | ||
148 | struct uwb_rsv *rsv, *found = NULL; | ||
149 | int i = 0; | ||
150 | |||
151 | list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) { | ||
152 | if (i == cmd->index) { | ||
153 | found = rsv; | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | if (!found) | ||
158 | return -EINVAL; | ||
159 | |||
160 | list_del(&found->pal_node); | ||
161 | uwb_rsv_terminate(found); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int command_open(struct inode *inode, struct file *file) | ||
167 | { | ||
168 | file->private_data = inode->i_private; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static ssize_t command_write(struct file *file, const char __user *buf, | ||
174 | size_t len, loff_t *off) | ||
175 | { | ||
176 | struct uwb_rc *rc = file->private_data; | ||
177 | struct uwb_dbg_cmd cmd; | ||
178 | int ret; | ||
179 | |||
180 | if (len != sizeof(struct uwb_dbg_cmd)) | ||
181 | return -EINVAL; | ||
182 | |||
183 | if (copy_from_user(&cmd, buf, len) != 0) | ||
184 | return -EFAULT; | ||
185 | |||
186 | switch (cmd.type) { | ||
187 | case UWB_DBG_CMD_RSV_ESTABLISH: | ||
188 | ret = cmd_rsv_establish(rc, &cmd.rsv_establish); | ||
189 | break; | ||
190 | case UWB_DBG_CMD_RSV_TERMINATE: | ||
191 | ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate); | ||
192 | break; | ||
193 | default: | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | return ret < 0 ? ret : len; | ||
198 | } | ||
199 | |||
200 | static struct file_operations command_fops = { | ||
201 | .open = command_open, | ||
202 | .write = command_write, | ||
203 | .read = NULL, | ||
204 | .llseek = no_llseek, | ||
205 | .owner = THIS_MODULE, | ||
206 | }; | ||
207 | |||
208 | static int reservations_print(struct seq_file *s, void *p) | ||
209 | { | ||
210 | struct uwb_rc *rc = s->private; | ||
211 | struct uwb_rsv *rsv; | ||
212 | |||
213 | mutex_lock(&rc->rsvs_mutex); | ||
214 | |||
215 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
216 | struct uwb_dev_addr devaddr; | ||
217 | char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; | ||
218 | bool is_owner; | ||
219 | char buf[72]; | ||
220 | |||
221 | uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); | ||
222 | if (rsv->target.type == UWB_RSV_TARGET_DEV) { | ||
223 | devaddr = rsv->target.dev->dev_addr; | ||
224 | is_owner = &rc->uwb_dev == rsv->owner; | ||
225 | } else { | ||
226 | devaddr = rsv->target.devaddr; | ||
227 | is_owner = true; | ||
228 | } | ||
229 | uwb_dev_addr_print(target, sizeof(target), &devaddr); | ||
230 | |||
231 | seq_printf(s, "%c %s -> %s: %s\n", | ||
232 | is_owner ? 'O' : 'T', | ||
233 | owner, target, uwb_rsv_state_str(rsv->state)); | ||
234 | seq_printf(s, " stream: %d type: %s\n", | ||
235 | rsv->stream, uwb_rsv_type_str(rsv->type)); | ||
236 | bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS); | ||
237 | seq_printf(s, " %s\n", buf); | ||
238 | } | ||
239 | |||
240 | mutex_unlock(&rc->rsvs_mutex); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int reservations_open(struct inode *inode, struct file *file) | ||
246 | { | ||
247 | return single_open(file, reservations_print, inode->i_private); | ||
248 | } | ||
249 | |||
250 | static struct file_operations reservations_fops = { | ||
251 | .open = reservations_open, | ||
252 | .read = seq_read, | ||
253 | .llseek = seq_lseek, | ||
254 | .release = single_release, | ||
255 | .owner = THIS_MODULE, | ||
256 | }; | ||
257 | |||
258 | static int drp_avail_print(struct seq_file *s, void *p) | ||
259 | { | ||
260 | struct uwb_rc *rc = s->private; | ||
261 | char buf[72]; | ||
262 | |||
263 | bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS); | ||
264 | seq_printf(s, "global: %s\n", buf); | ||
265 | bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS); | ||
266 | seq_printf(s, "local: %s\n", buf); | ||
267 | bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS); | ||
268 | seq_printf(s, "pending: %s\n", buf); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int drp_avail_open(struct inode *inode, struct file *file) | ||
274 | { | ||
275 | return single_open(file, drp_avail_print, inode->i_private); | ||
276 | } | ||
277 | |||
278 | static struct file_operations drp_avail_fops = { | ||
279 | .open = drp_avail_open, | ||
280 | .read = seq_read, | ||
281 | .llseek = seq_lseek, | ||
282 | .release = single_release, | ||
283 | .owner = THIS_MODULE, | ||
284 | }; | ||
285 | |||
286 | static void uwb_dbg_new_rsv(struct uwb_rsv *rsv) | ||
287 | { | ||
288 | struct uwb_rc *rc = rsv->rc; | ||
289 | |||
290 | if (rc->dbg->accept) | ||
291 | uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * uwb_dbg_add_rc - add a debug interface for a radio controller | ||
296 | * @rc: the radio controller | ||
297 | */ | ||
298 | void uwb_dbg_add_rc(struct uwb_rc *rc) | ||
299 | { | ||
300 | rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL); | ||
301 | if (rc->dbg == NULL) | ||
302 | return; | ||
303 | |||
304 | INIT_LIST_HEAD(&rc->dbg->rsvs); | ||
305 | |||
306 | uwb_pal_init(&rc->dbg->pal); | ||
307 | rc->dbg->pal.new_rsv = uwb_dbg_new_rsv; | ||
308 | uwb_pal_register(rc, &rc->dbg->pal); | ||
309 | if (root_dir) { | ||
310 | rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev), | ||
311 | root_dir); | ||
312 | rc->dbg->command_f = debugfs_create_file("command", 0200, | ||
313 | rc->dbg->root_d, rc, | ||
314 | &command_fops); | ||
315 | rc->dbg->reservations_f = debugfs_create_file("reservations", 0444, | ||
316 | rc->dbg->root_d, rc, | ||
317 | &reservations_fops); | ||
318 | rc->dbg->accept_f = debugfs_create_bool("accept", 0644, | ||
319 | rc->dbg->root_d, | ||
320 | &rc->dbg->accept); | ||
321 | rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444, | ||
322 | rc->dbg->root_d, rc, | ||
323 | &drp_avail_fops); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * uwb_dbg_add_rc - remove a radio controller's debug interface | ||
329 | * @rc: the radio controller | ||
330 | */ | ||
331 | void uwb_dbg_del_rc(struct uwb_rc *rc) | ||
332 | { | ||
333 | struct uwb_rsv *rsv, *t; | ||
334 | |||
335 | if (rc->dbg == NULL) | ||
336 | return; | ||
337 | |||
338 | list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) { | ||
339 | uwb_rsv_destroy(rsv); | ||
340 | } | ||
341 | |||
342 | uwb_pal_unregister(rc, &rc->dbg->pal); | ||
343 | |||
344 | if (root_dir) { | ||
345 | debugfs_remove(rc->dbg->drp_avail_f); | ||
346 | debugfs_remove(rc->dbg->accept_f); | ||
347 | debugfs_remove(rc->dbg->reservations_f); | ||
348 | debugfs_remove(rc->dbg->command_f); | ||
349 | debugfs_remove(rc->dbg->root_d); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * uwb_dbg_exit - initialize the debug interface sub-module | ||
355 | */ | ||
356 | void uwb_dbg_init(void) | ||
357 | { | ||
358 | root_dir = debugfs_create_dir("uwb", NULL); | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * uwb_dbg_exit - clean-up the debug interface sub-module | ||
363 | */ | ||
364 | void uwb_dbg_exit(void) | ||
365 | { | ||
366 | debugfs_remove(root_dir); | ||
367 | } | ||
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h new file mode 100644 index 000000000000..2ad307d12961 --- /dev/null +++ b/drivers/uwb/uwb-internal.h | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * UWB internal API | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * This contains most of the internal API for UWB. This is stuff used | ||
23 | * across the stack that of course, is of no interest to the rest. | ||
24 | * | ||
25 | * Some parts might end up going public (like uwb_rc_*())... | ||
26 | */ | ||
27 | |||
28 | #ifndef __UWB_INTERNAL_H__ | ||
29 | #define __UWB_INTERNAL_H__ | ||
30 | |||
31 | #include <linux/version.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/uwb.h> | ||
35 | #include <linux/mutex.h> | ||
36 | |||
37 | struct uwb_beca_e; | ||
38 | |||
39 | /* General device API */ | ||
40 | extern void uwb_dev_init(struct uwb_dev *uwb_dev); | ||
41 | extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *); | ||
42 | extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev, | ||
43 | struct uwb_rc *parent_rc); | ||
44 | extern void uwb_dev_rm(struct uwb_dev *uwb_dev); | ||
45 | extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *); | ||
46 | extern void uwbd_dev_offair(struct uwb_beca_e *); | ||
47 | void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event); | ||
48 | |||
49 | /* General UWB Radio Controller Internal API */ | ||
50 | extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *); | ||
51 | static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc) | ||
52 | { | ||
53 | uwb_dev_get(&rc->uwb_dev); | ||
54 | return rc; | ||
55 | } | ||
56 | |||
57 | static inline void __uwb_rc_put(struct uwb_rc *rc) | ||
58 | { | ||
59 | uwb_dev_put(&rc->uwb_dev); | ||
60 | } | ||
61 | |||
62 | extern int uwb_rc_reset(struct uwb_rc *rc); | ||
63 | extern int uwb_rc_beacon(struct uwb_rc *rc, | ||
64 | int channel, unsigned bpst_offset); | ||
65 | extern int uwb_rc_scan(struct uwb_rc *rc, | ||
66 | unsigned channel, enum uwb_scan_type type, | ||
67 | unsigned bpst_offset); | ||
68 | extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc); | ||
69 | extern ssize_t uwb_rc_print_IEs(struct uwb_rc *rc, char *, size_t); | ||
70 | extern void uwb_rc_ie_init(struct uwb_rc *); | ||
71 | extern void uwb_rc_ie_init(struct uwb_rc *); | ||
72 | extern ssize_t uwb_rc_ie_setup(struct uwb_rc *); | ||
73 | extern void uwb_rc_ie_release(struct uwb_rc *); | ||
74 | extern int uwb_rc_ie_add(struct uwb_rc *, | ||
75 | const struct uwb_ie_hdr *, size_t); | ||
76 | extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie); | ||
77 | |||
78 | extern const char *uwb_rc_strerror(unsigned code); | ||
79 | |||
80 | /* | ||
81 | * Time to wait for a response to an RC command. | ||
82 | * | ||
83 | * Some commands can take a long time to response. e.g., START_BEACON | ||
84 | * may scan for several superframes before joining an existing beacon | ||
85 | * group and this can take around 600 ms. | ||
86 | */ | ||
87 | #define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */ | ||
88 | |||
89 | /* | ||
90 | * Notification/Event Handlers | ||
91 | */ | ||
92 | |||
93 | struct uwb_rc_neh; | ||
94 | |||
95 | void uwb_rc_neh_create(struct uwb_rc *rc); | ||
96 | void uwb_rc_neh_destroy(struct uwb_rc *rc); | ||
97 | |||
98 | struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd, | ||
99 | u8 expected_type, u16 expected_event, | ||
100 | uwb_rc_cmd_cb_f cb, void *arg); | ||
101 | void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh); | ||
102 | void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh); | ||
103 | void uwb_rc_neh_put(struct uwb_rc_neh *neh); | ||
104 | |||
105 | /* Event size tables */ | ||
106 | extern int uwb_est_create(void); | ||
107 | extern void uwb_est_destroy(void); | ||
108 | |||
109 | |||
110 | /* | ||
111 | * UWB Events & management daemon | ||
112 | */ | ||
113 | |||
114 | /** | ||
115 | * enum uwb_event_type - types of UWB management daemon events | ||
116 | * | ||
117 | * The UWB management daemon (uwbd) can receive two types of events: | ||
118 | * UWB_EVT_TYPE_NOTIF - notification from the radio controller. | ||
119 | * UWB_EVT_TYPE_MSG - a simple message. | ||
120 | */ | ||
121 | enum uwb_event_type { | ||
122 | UWB_EVT_TYPE_NOTIF, | ||
123 | UWB_EVT_TYPE_MSG, | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * struct uwb_event_notif - an event for a radio controller notification | ||
128 | * @size: Size of the buffer (ie: Guaranteed to contain at least | ||
129 | * a full 'struct uwb_rceb') | ||
130 | * @rceb: Pointer to a kmalloced() event payload | ||
131 | */ | ||
132 | struct uwb_event_notif { | ||
133 | size_t size; | ||
134 | struct uwb_rceb *rceb; | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * enum uwb_event_message - an event for a message for asynchronous processing | ||
139 | * | ||
140 | * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware. | ||
141 | */ | ||
142 | enum uwb_event_message { | ||
143 | UWB_EVT_MSG_RESET, | ||
144 | }; | ||
145 | |||
146 | /** | ||
147 | * UWB Event | ||
148 | * @rc: Radio controller that emitted the event (referenced) | ||
149 | * @ts_jiffies: Timestamp, when was it received | ||
150 | * @type: This event's type. | ||
151 | */ | ||
152 | struct uwb_event { | ||
153 | struct list_head list_node; | ||
154 | struct uwb_rc *rc; | ||
155 | unsigned long ts_jiffies; | ||
156 | enum uwb_event_type type; | ||
157 | union { | ||
158 | struct uwb_event_notif notif; | ||
159 | enum uwb_event_message message; | ||
160 | }; | ||
161 | }; | ||
162 | |||
163 | extern void uwbd_start(void); | ||
164 | extern void uwbd_stop(void); | ||
165 | extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask); | ||
166 | extern void uwbd_event_queue(struct uwb_event *); | ||
167 | void uwbd_flush(struct uwb_rc *rc); | ||
168 | |||
169 | /* UWB event handlers */ | ||
170 | extern int uwbd_evt_handle_rc_beacon(struct uwb_event *); | ||
171 | extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *); | ||
172 | extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *); | ||
173 | extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *); | ||
174 | extern int uwbd_evt_handle_rc_drp(struct uwb_event *); | ||
175 | extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *); | ||
176 | |||
177 | int uwbd_msg_handle_reset(struct uwb_event *evt); | ||
178 | |||
179 | |||
180 | /* | ||
181 | * Address management | ||
182 | */ | ||
183 | int uwb_rc_dev_addr_assign(struct uwb_rc *rc); | ||
184 | int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt); | ||
185 | |||
186 | /* | ||
187 | * UWB Beacon Cache | ||
188 | * | ||
189 | * Each beacon we received is kept in a cache--when we receive that | ||
190 | * beacon consistently, that means there is a new device that we have | ||
191 | * to add to the system. | ||
192 | */ | ||
193 | |||
194 | extern unsigned long beacon_timeout_ms; | ||
195 | |||
196 | /** Beacon cache list */ | ||
197 | struct uwb_beca { | ||
198 | struct list_head list; | ||
199 | size_t entries; | ||
200 | struct mutex mutex; | ||
201 | }; | ||
202 | |||
203 | extern struct uwb_beca uwb_beca; | ||
204 | |||
205 | /** | ||
206 | * Beacon cache entry | ||
207 | * | ||
208 | * @jiffies_refresh: last time a beacon was received that refreshed | ||
209 | * this cache entry. | ||
210 | * @uwb_dev: device connected to this beacon. This pointer is not | ||
211 | * safe, you need to get it with uwb_dev_try_get() | ||
212 | * | ||
213 | * @hits: how many time we have seen this beacon since last time we | ||
214 | * cleared it | ||
215 | */ | ||
216 | struct uwb_beca_e { | ||
217 | struct mutex mutex; | ||
218 | struct kref refcnt; | ||
219 | struct list_head node; | ||
220 | struct uwb_mac_addr *mac_addr; | ||
221 | struct uwb_dev_addr dev_addr; | ||
222 | u8 hits; | ||
223 | unsigned long ts_jiffies; | ||
224 | struct uwb_dev *uwb_dev; | ||
225 | struct uwb_rc_evt_beacon *be; | ||
226 | struct stats lqe_stats, rssi_stats; /* radio statistics */ | ||
227 | }; | ||
228 | struct uwb_beacon_frame; | ||
229 | extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *, | ||
230 | char *, size_t); | ||
231 | extern struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *, | ||
232 | struct uwb_beacon_frame *, | ||
233 | unsigned long); | ||
234 | |||
235 | extern void uwb_bce_kfree(struct kref *_bce); | ||
236 | static inline void uwb_bce_get(struct uwb_beca_e *bce) | ||
237 | { | ||
238 | kref_get(&bce->refcnt); | ||
239 | } | ||
240 | static inline void uwb_bce_put(struct uwb_beca_e *bce) | ||
241 | { | ||
242 | kref_put(&bce->refcnt, uwb_bce_kfree); | ||
243 | } | ||
244 | extern void uwb_beca_purge(void); | ||
245 | extern void uwb_beca_release(void); | ||
246 | |||
247 | struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, | ||
248 | const struct uwb_dev_addr *devaddr); | ||
249 | struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, | ||
250 | const struct uwb_mac_addr *macaddr); | ||
251 | |||
252 | /* -- UWB Sysfs representation */ | ||
253 | extern struct class uwb_rc_class; | ||
254 | extern struct device_attribute dev_attr_mac_address; | ||
255 | extern struct device_attribute dev_attr_beacon; | ||
256 | extern struct device_attribute dev_attr_scan; | ||
257 | |||
258 | /* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */ | ||
259 | void uwb_rsv_init(struct uwb_rc *rc); | ||
260 | int uwb_rsv_setup(struct uwb_rc *rc); | ||
261 | void uwb_rsv_cleanup(struct uwb_rc *rc); | ||
262 | |||
263 | void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state); | ||
264 | void uwb_rsv_remove(struct uwb_rsv *rsv); | ||
265 | struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, | ||
266 | struct uwb_ie_drp *drp_ie); | ||
267 | void uwb_rsv_sched_update(struct uwb_rc *rc); | ||
268 | |||
269 | void uwb_drp_handle_timeout(struct uwb_rsv *rsv); | ||
270 | int uwb_drp_ie_update(struct uwb_rsv *rsv); | ||
271 | void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie); | ||
272 | |||
273 | void uwb_drp_avail_init(struct uwb_rc *rc); | ||
274 | int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas); | ||
275 | void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas); | ||
276 | void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas); | ||
277 | void uwb_drp_avail_ie_update(struct uwb_rc *rc); | ||
278 | |||
279 | /* -- PAL support */ | ||
280 | void uwb_rc_pal_init(struct uwb_rc *rc); | ||
281 | |||
282 | /* -- Misc */ | ||
283 | |||
284 | extern ssize_t uwb_mac_frame_hdr_print(char *, size_t, | ||
285 | const struct uwb_mac_frame_hdr *); | ||
286 | |||
287 | /* -- Debug interface */ | ||
288 | void uwb_dbg_init(void); | ||
289 | void uwb_dbg_exit(void); | ||
290 | void uwb_dbg_add_rc(struct uwb_rc *rc); | ||
291 | void uwb_dbg_del_rc(struct uwb_rc *rc); | ||
292 | |||
293 | /* Workarounds for version specific stuff */ | ||
294 | |||
295 | static inline void uwb_dev_lock(struct uwb_dev *uwb_dev) | ||
296 | { | ||
297 | down(&uwb_dev->dev.sem); | ||
298 | } | ||
299 | |||
300 | static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev) | ||
301 | { | ||
302 | up(&uwb_dev->dev.sem); | ||
303 | } | ||
304 | |||
305 | #endif /* #ifndef __UWB_INTERNAL_H__ */ | ||
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c new file mode 100644 index 000000000000..78908416e42c --- /dev/null +++ b/drivers/uwb/uwbd.c | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Neighborhood Management Daemon | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * This daemon takes care of maintaing information that describes the | ||
24 | * UWB neighborhood that the radios in this machine can see. It also | ||
25 | * keeps a tab of which devices are visible, makes sure each HC sits | ||
26 | * on a different channel to avoid interfering, etc. | ||
27 | * | ||
28 | * Different drivers (radio controller, device, any API in general) | ||
29 | * communicate with this daemon through an event queue. Daemon wakes | ||
30 | * up, takes a list of events and handles them one by one; handling | ||
31 | * function is extracted from a table based on the event's type and | ||
32 | * subtype. Events are freed only if the handling function says so. | ||
33 | * | ||
34 | * . Lock protecting the event list has to be an spinlock and locked | ||
35 | * with IRQSAVE because it might be called from an interrupt | ||
36 | * context (ie: when events arrive and the notification drops | ||
37 | * down from the ISR). | ||
38 | * | ||
39 | * . UWB radio controller drivers queue events to the daemon using | ||
40 | * uwbd_event_queue(). They just get the event, chew it to make it | ||
41 | * look like UWBD likes it and pass it in a buffer allocated with | ||
42 | * uwb_event_alloc(). | ||
43 | * | ||
44 | * EVENTS | ||
45 | * | ||
46 | * Events have a type, a subtype, a lenght, some other stuff and the | ||
47 | * data blob, which depends on the event. The header is 'struct | ||
48 | * uwb_event'; for payloads, see 'struct uwbd_evt_*'. | ||
49 | * | ||
50 | * EVENT HANDLER TABLES | ||
51 | * | ||
52 | * To find a handling function for an event, the type is used to index | ||
53 | * a subtype-table in the type-table. The subtype-table is indexed | ||
54 | * with the subtype to get the function that handles the event. Start | ||
55 | * with the main type-table 'uwbd_evt_type_handler'. | ||
56 | * | ||
57 | * DEVICES | ||
58 | * | ||
59 | * Devices are created when a bunch of beacons have been received and | ||
60 | * it is stablished that the device has stable radio presence. CREATED | ||
61 | * only, not configured. Devices are ONLY configured when an | ||
62 | * Application-Specific IE Probe is receieved, in which the device | ||
63 | * declares which Protocol ID it groks. Then the device is CONFIGURED | ||
64 | * (and the driver->probe() stuff of the device model is invoked). | ||
65 | * | ||
66 | * Devices are considered disconnected when a certain number of | ||
67 | * beacons are not received in an amount of time. | ||
68 | * | ||
69 | * Handler functions are called normally uwbd_evt_handle_*(). | ||
70 | */ | ||
71 | |||
72 | #include <linux/kthread.h> | ||
73 | #include <linux/module.h> | ||
74 | #include <linux/freezer.h> | ||
75 | #include "uwb-internal.h" | ||
76 | |||
77 | #define D_LOCAL 1 | ||
78 | #include <linux/uwb/debug.h> | ||
79 | |||
80 | |||
81 | /** | ||
82 | * UWBD Event handler function signature | ||
83 | * | ||
84 | * Return !0 if the event needs not to be freed (ie the handler | ||
85 | * takes/took care of it). 0 means the daemon code will free the | ||
86 | * event. | ||
87 | * | ||
88 | * @evt->rc is already referenced and guaranteed to exist. See | ||
89 | * uwb_evt_handle(). | ||
90 | */ | ||
91 | typedef int (*uwbd_evt_handler_f)(struct uwb_event *); | ||
92 | |||
93 | /** | ||
94 | * Properties of a UWBD event | ||
95 | * | ||
96 | * @handler: the function that will handle this event | ||
97 | * @name: text name of event | ||
98 | */ | ||
99 | struct uwbd_event { | ||
100 | uwbd_evt_handler_f handler; | ||
101 | const char *name; | ||
102 | }; | ||
103 | |||
104 | /** Table of handlers for and properties of the UWBD Radio Control Events */ | ||
105 | static | ||
106 | struct uwbd_event uwbd_events[] = { | ||
107 | [UWB_RC_EVT_BEACON] = { | ||
108 | .handler = uwbd_evt_handle_rc_beacon, | ||
109 | .name = "BEACON_RECEIVED" | ||
110 | }, | ||
111 | [UWB_RC_EVT_BEACON_SIZE] = { | ||
112 | .handler = uwbd_evt_handle_rc_beacon_size, | ||
113 | .name = "BEACON_SIZE_CHANGE" | ||
114 | }, | ||
115 | [UWB_RC_EVT_BPOIE_CHANGE] = { | ||
116 | .handler = uwbd_evt_handle_rc_bpoie_change, | ||
117 | .name = "BPOIE_CHANGE" | ||
118 | }, | ||
119 | [UWB_RC_EVT_BP_SLOT_CHANGE] = { | ||
120 | .handler = uwbd_evt_handle_rc_bp_slot_change, | ||
121 | .name = "BP_SLOT_CHANGE" | ||
122 | }, | ||
123 | [UWB_RC_EVT_DRP_AVAIL] = { | ||
124 | .handler = uwbd_evt_handle_rc_drp_avail, | ||
125 | .name = "DRP_AVAILABILITY_CHANGE" | ||
126 | }, | ||
127 | [UWB_RC_EVT_DRP] = { | ||
128 | .handler = uwbd_evt_handle_rc_drp, | ||
129 | .name = "DRP" | ||
130 | }, | ||
131 | [UWB_RC_EVT_DEV_ADDR_CONFLICT] = { | ||
132 | .handler = uwbd_evt_handle_rc_dev_addr_conflict, | ||
133 | .name = "DEV_ADDR_CONFLICT", | ||
134 | }, | ||
135 | }; | ||
136 | |||
137 | |||
138 | |||
139 | struct uwbd_evt_type_handler { | ||
140 | const char *name; | ||
141 | struct uwbd_event *uwbd_events; | ||
142 | size_t size; | ||
143 | }; | ||
144 | |||
145 | #define UWBD_EVT_TYPE_HANDLER(n,a) { \ | ||
146 | .name = (n), \ | ||
147 | .uwbd_events = (a), \ | ||
148 | .size = sizeof(a)/sizeof((a)[0]) \ | ||
149 | } | ||
150 | |||
151 | |||
152 | /** Table of handlers for each UWBD Event type. */ | ||
153 | static | ||
154 | struct uwbd_evt_type_handler uwbd_evt_type_handlers[] = { | ||
155 | [UWB_RC_CET_GENERAL] = UWBD_EVT_TYPE_HANDLER("RC", uwbd_events) | ||
156 | }; | ||
157 | |||
158 | static const | ||
159 | size_t uwbd_evt_type_handlers_len = | ||
160 | sizeof(uwbd_evt_type_handlers) / sizeof(uwbd_evt_type_handlers[0]); | ||
161 | |||
162 | static const struct uwbd_event uwbd_message_handlers[] = { | ||
163 | [UWB_EVT_MSG_RESET] = { | ||
164 | .handler = uwbd_msg_handle_reset, | ||
165 | .name = "reset", | ||
166 | }, | ||
167 | }; | ||
168 | |||
169 | static DEFINE_MUTEX(uwbd_event_mutex); | ||
170 | |||
171 | /** | ||
172 | * Handle an URC event passed to the UWB Daemon | ||
173 | * | ||
174 | * @evt: the event to handle | ||
175 | * @returns: 0 if the event can be kfreed, !0 on the contrary | ||
176 | * (somebody else took ownership) [coincidentally, returning | ||
177 | * a <0 errno code will free it :)]. | ||
178 | * | ||
179 | * Looks up the two indirection tables (one for the type, one for the | ||
180 | * subtype) to decide which function handles it and then calls the | ||
181 | * handler. | ||
182 | * | ||
183 | * The event structure passed to the event handler has the radio | ||
184 | * controller in @evt->rc referenced. The reference will be dropped | ||
185 | * once the handler returns, so if it needs it for longer (async), | ||
186 | * it'll need to take another one. | ||
187 | */ | ||
188 | static | ||
189 | int uwbd_event_handle_urc(struct uwb_event *evt) | ||
190 | { | ||
191 | struct uwbd_evt_type_handler *type_table; | ||
192 | uwbd_evt_handler_f handler; | ||
193 | u8 type, context; | ||
194 | u16 event; | ||
195 | |||
196 | type = evt->notif.rceb->bEventType; | ||
197 | event = le16_to_cpu(evt->notif.rceb->wEvent); | ||
198 | context = evt->notif.rceb->bEventContext; | ||
199 | |||
200 | if (type > uwbd_evt_type_handlers_len) { | ||
201 | printk(KERN_ERR "UWBD: event type %u: unknown (too high)\n", type); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | type_table = &uwbd_evt_type_handlers[type]; | ||
205 | if (type_table->uwbd_events == NULL) { | ||
206 | printk(KERN_ERR "UWBD: event type %u: unknown\n", type); | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | if (event > type_table->size) { | ||
210 | printk(KERN_ERR "UWBD: event %s[%u]: unknown (too high)\n", | ||
211 | type_table->name, event); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | handler = type_table->uwbd_events[event].handler; | ||
215 | if (handler == NULL) { | ||
216 | printk(KERN_ERR "UWBD: event %s[%u]: unknown\n", type_table->name, event); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | return (*handler)(evt); | ||
220 | } | ||
221 | |||
222 | static void uwbd_event_handle_message(struct uwb_event *evt) | ||
223 | { | ||
224 | struct uwb_rc *rc; | ||
225 | int result; | ||
226 | |||
227 | rc = evt->rc; | ||
228 | |||
229 | if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) { | ||
230 | dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | /* If this is a reset event we need to drop the | ||
235 | * uwbd_event_mutex or it deadlocks when the reset handler | ||
236 | * attempts to flush the uwbd events. */ | ||
237 | if (evt->message == UWB_EVT_MSG_RESET) | ||
238 | mutex_unlock(&uwbd_event_mutex); | ||
239 | |||
240 | result = uwbd_message_handlers[evt->message].handler(evt); | ||
241 | if (result < 0) | ||
242 | dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n", | ||
243 | uwbd_message_handlers[evt->message].name, result); | ||
244 | |||
245 | if (evt->message == UWB_EVT_MSG_RESET) | ||
246 | mutex_lock(&uwbd_event_mutex); | ||
247 | } | ||
248 | |||
249 | static void uwbd_event_handle(struct uwb_event *evt) | ||
250 | { | ||
251 | struct uwb_rc *rc; | ||
252 | int should_keep; | ||
253 | |||
254 | rc = evt->rc; | ||
255 | |||
256 | if (rc->ready) { | ||
257 | switch (evt->type) { | ||
258 | case UWB_EVT_TYPE_NOTIF: | ||
259 | should_keep = uwbd_event_handle_urc(evt); | ||
260 | if (should_keep <= 0) | ||
261 | kfree(evt->notif.rceb); | ||
262 | break; | ||
263 | case UWB_EVT_TYPE_MSG: | ||
264 | uwbd_event_handle_message(evt); | ||
265 | break; | ||
266 | default: | ||
267 | dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type); | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */ | ||
273 | } | ||
274 | /* The UWB Daemon */ | ||
275 | |||
276 | |||
277 | /** Daemon's PID: used to decide if we can queue or not */ | ||
278 | static int uwbd_pid; | ||
279 | /** Daemon's task struct for managing the kthread */ | ||
280 | static struct task_struct *uwbd_task; | ||
281 | /** Daemon's waitqueue for waiting for new events */ | ||
282 | static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq); | ||
283 | /** Daemon's list of events; we queue/dequeue here */ | ||
284 | static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list); | ||
285 | /** Daemon's list lock to protect concurent access */ | ||
286 | static DEFINE_SPINLOCK(uwbd_event_list_lock); | ||
287 | |||
288 | |||
289 | /** | ||
290 | * UWB Daemon | ||
291 | * | ||
292 | * Listens to all UWB notifications and takes care to track the state | ||
293 | * of the UWB neighboorhood for the kernel. When we do a run, we | ||
294 | * spinlock, move the list to a private copy and release the | ||
295 | * lock. Hold it as little as possible. Not a conflict: it is | ||
296 | * guaranteed we own the events in the private list. | ||
297 | * | ||
298 | * FIXME: should change so we don't have a 1HZ timer all the time, but | ||
299 | * only if there are devices. | ||
300 | */ | ||
301 | static int uwbd(void *unused) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | struct list_head list = LIST_HEAD_INIT(list); | ||
305 | struct uwb_event *evt, *nxt; | ||
306 | int should_stop = 0; | ||
307 | while (1) { | ||
308 | wait_event_interruptible_timeout( | ||
309 | uwbd_wq, | ||
310 | !list_empty(&uwbd_event_list) | ||
311 | || (should_stop = kthread_should_stop()), | ||
312 | HZ); | ||
313 | if (should_stop) | ||
314 | break; | ||
315 | try_to_freeze(); | ||
316 | |||
317 | mutex_lock(&uwbd_event_mutex); | ||
318 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | ||
319 | list_splice_init(&uwbd_event_list, &list); | ||
320 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | ||
321 | list_for_each_entry_safe(evt, nxt, &list, list_node) { | ||
322 | list_del(&evt->list_node); | ||
323 | uwbd_event_handle(evt); | ||
324 | kfree(evt); | ||
325 | } | ||
326 | mutex_unlock(&uwbd_event_mutex); | ||
327 | |||
328 | uwb_beca_purge(); /* Purge devices that left */ | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | |||
334 | /** Start the UWB daemon */ | ||
335 | void uwbd_start(void) | ||
336 | { | ||
337 | uwbd_task = kthread_run(uwbd, NULL, "uwbd"); | ||
338 | if (uwbd_task == NULL) | ||
339 | printk(KERN_ERR "UWB: Cannot start management daemon; " | ||
340 | "UWB won't work\n"); | ||
341 | else | ||
342 | uwbd_pid = uwbd_task->pid; | ||
343 | } | ||
344 | |||
345 | /* Stop the UWB daemon and free any unprocessed events */ | ||
346 | void uwbd_stop(void) | ||
347 | { | ||
348 | unsigned long flags; | ||
349 | struct uwb_event *evt, *nxt; | ||
350 | kthread_stop(uwbd_task); | ||
351 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | ||
352 | uwbd_pid = 0; | ||
353 | list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { | ||
354 | if (evt->type == UWB_EVT_TYPE_NOTIF) | ||
355 | kfree(evt->notif.rceb); | ||
356 | kfree(evt); | ||
357 | } | ||
358 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | ||
359 | uwb_beca_release(); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Queue an event for the management daemon | ||
364 | * | ||
365 | * When some lower layer receives an event, it uses this function to | ||
366 | * push it forward to the UWB daemon. | ||
367 | * | ||
368 | * Once you pass the event, you don't own it any more, but the daemon | ||
369 | * does. It will uwb_event_free() it when done, so make sure you | ||
370 | * uwb_event_alloc()ed it or bad things will happen. | ||
371 | * | ||
372 | * If the daemon is not running, we just free the event. | ||
373 | */ | ||
374 | void uwbd_event_queue(struct uwb_event *evt) | ||
375 | { | ||
376 | unsigned long flags; | ||
377 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | ||
378 | if (uwbd_pid != 0) { | ||
379 | list_add(&evt->list_node, &uwbd_event_list); | ||
380 | wake_up_all(&uwbd_wq); | ||
381 | } else { | ||
382 | __uwb_rc_put(evt->rc); | ||
383 | if (evt->type == UWB_EVT_TYPE_NOTIF) | ||
384 | kfree(evt->notif.rceb); | ||
385 | kfree(evt); | ||
386 | } | ||
387 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | void uwbd_flush(struct uwb_rc *rc) | ||
392 | { | ||
393 | struct uwb_event *evt, *nxt; | ||
394 | |||
395 | mutex_lock(&uwbd_event_mutex); | ||
396 | |||
397 | spin_lock_irq(&uwbd_event_list_lock); | ||
398 | list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { | ||
399 | if (evt->rc == rc) { | ||
400 | __uwb_rc_put(rc); | ||
401 | list_del(&evt->list_node); | ||
402 | if (evt->type == UWB_EVT_TYPE_NOTIF) | ||
403 | kfree(evt->notif.rceb); | ||
404 | kfree(evt); | ||
405 | } | ||
406 | } | ||
407 | spin_unlock_irq(&uwbd_event_list_lock); | ||
408 | |||
409 | mutex_unlock(&uwbd_event_mutex); | ||
410 | } | ||
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c new file mode 100644 index 000000000000..1711deadb114 --- /dev/null +++ b/drivers/uwb/whc-rc.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3]) | ||
3 | * Radio Control command/event transport to the UWB stack | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * Initialize and hook up the Radio Control interface. | ||
24 | * | ||
25 | * For each device probed, creates an 'struct whcrc' which contains | ||
26 | * just the representation of the UWB Radio Controller, and the logic | ||
27 | * for reading notifications and passing them to the UWB Core. | ||
28 | * | ||
29 | * So we initialize all of those, register the UWB Radio Controller | ||
30 | * and setup the notification/event handle to pipe the notifications | ||
31 | * to the UWB management Daemon. | ||
32 | * | ||
33 | * Once uwb_rc_add() is called, the UWB stack takes control, resets | ||
34 | * the radio and readies the device to take commands the UWB | ||
35 | * API/user-space. | ||
36 | * | ||
37 | * Note this driver is just a transport driver; the commands are | ||
38 | * formed at the UWB stack and given to this driver who will deliver | ||
39 | * them to the hw and transfer the replies/notifications back to the | ||
40 | * UWB stack through the UWB daemon (UWBD). | ||
41 | */ | ||
42 | #include <linux/version.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/module.h> | ||
45 | #include <linux/pci.h> | ||
46 | #include <linux/dma-mapping.h> | ||
47 | #include <linux/interrupt.h> | ||
48 | #include <linux/workqueue.h> | ||
49 | #include <linux/uwb.h> | ||
50 | #include <linux/uwb/whci.h> | ||
51 | #include <linux/uwb/umc.h> | ||
52 | #include "uwb-internal.h" | ||
53 | |||
54 | #define D_LOCAL 0 | ||
55 | #include <linux/uwb/debug.h> | ||
56 | |||
57 | /** | ||
58 | * Descriptor for an instance of the UWB Radio Control Driver that | ||
59 | * attaches to the URC interface of the WHCI PCI card. | ||
60 | * | ||
61 | * Unless there is a lock specific to the 'data members', all access | ||
62 | * is protected by uwb_rc->mutex. | ||
63 | */ | ||
64 | struct whcrc { | ||
65 | struct umc_dev *umc_dev; | ||
66 | struct uwb_rc *uwb_rc; /* UWB host controller */ | ||
67 | |||
68 | unsigned long area; | ||
69 | void __iomem *rc_base; | ||
70 | size_t rc_len; | ||
71 | spinlock_t irq_lock; | ||
72 | |||
73 | void *evt_buf, *cmd_buf; | ||
74 | dma_addr_t evt_dma_buf, cmd_dma_buf; | ||
75 | wait_queue_head_t cmd_wq; | ||
76 | struct work_struct event_work; | ||
77 | }; | ||
78 | |||
79 | /** | ||
80 | * Execute an UWB RC command on WHCI/RC | ||
81 | * | ||
82 | * @rc: Instance of a Radio Controller that is a whcrc | ||
83 | * @cmd: Buffer containing the RCCB and payload to execute | ||
84 | * @cmd_size: Size of the command buffer. | ||
85 | * | ||
86 | * We copy the command into whcrc->cmd_buf (as it is pretty and | ||
87 | * aligned`and physically contiguous) and then press the right keys in | ||
88 | * the controller's URCCMD register to get it to read it. We might | ||
89 | * have to wait for the cmd_sem to be open to us. | ||
90 | * | ||
91 | * NOTE: rc's mutex has to be locked | ||
92 | */ | ||
93 | static int whcrc_cmd(struct uwb_rc *uwb_rc, | ||
94 | const struct uwb_rccb *cmd, size_t cmd_size) | ||
95 | { | ||
96 | int result = 0; | ||
97 | struct whcrc *whcrc = uwb_rc->priv; | ||
98 | struct device *dev = &whcrc->umc_dev->dev; | ||
99 | u32 urccmd; | ||
100 | |||
101 | d_fnstart(3, dev, "(%p, %p, %zu)\n", uwb_rc, cmd, cmd_size); | ||
102 | might_sleep(); | ||
103 | |||
104 | if (cmd_size >= 4096) { | ||
105 | result = -E2BIG; | ||
106 | goto error; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * If the URC is halted, then the hardware has reset itself. | ||
111 | * Attempt to recover by restarting the device and then return | ||
112 | * an error as it's likely that the current command isn't | ||
113 | * valid for a newly started RC. | ||
114 | */ | ||
115 | if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) { | ||
116 | dev_err(dev, "requesting reset of halted radio controller\n"); | ||
117 | uwb_rc_reset_all(uwb_rc); | ||
118 | result = -EIO; | ||
119 | goto error; | ||
120 | } | ||
121 | |||
122 | result = wait_event_timeout(whcrc->cmd_wq, | ||
123 | !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2); | ||
124 | if (result == 0) { | ||
125 | dev_err(dev, "device is not ready to execute commands\n"); | ||
126 | result = -ETIMEDOUT; | ||
127 | goto error; | ||
128 | } | ||
129 | |||
130 | memmove(whcrc->cmd_buf, cmd, cmd_size); | ||
131 | le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR); | ||
132 | |||
133 | spin_lock(&whcrc->irq_lock); | ||
134 | urccmd = le_readl(whcrc->rc_base + URCCMD); | ||
135 | urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK); | ||
136 | le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size, | ||
137 | whcrc->rc_base + URCCMD); | ||
138 | spin_unlock(&whcrc->irq_lock); | ||
139 | |||
140 | error: | ||
141 | d_fnend(3, dev, "(%p, %p, %zu) = %d\n", | ||
142 | uwb_rc, cmd, cmd_size, result); | ||
143 | return result; | ||
144 | } | ||
145 | |||
146 | static int whcrc_reset(struct uwb_rc *rc) | ||
147 | { | ||
148 | struct whcrc *whcrc = rc->priv; | ||
149 | |||
150 | return umc_controller_reset(whcrc->umc_dev); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * Reset event reception mechanism and tell hw we are ready to get more | ||
155 | * | ||
156 | * We have read all the events in the event buffer, so we are ready to | ||
157 | * reset it to the beginning. | ||
158 | * | ||
159 | * This is only called during initialization or after an event buffer | ||
160 | * has been retired. This means we can be sure that event processing | ||
161 | * is disabled and it's safe to update the URCEVTADDR register. | ||
162 | * | ||
163 | * There's no need to wait for the event processing to start as the | ||
164 | * URC will not clear URCCMD_ACTIVE until (internal) event buffer | ||
165 | * space is available. | ||
166 | */ | ||
167 | static | ||
168 | void whcrc_enable_events(struct whcrc *whcrc) | ||
169 | { | ||
170 | struct device *dev = &whcrc->umc_dev->dev; | ||
171 | u32 urccmd; | ||
172 | |||
173 | d_fnstart(4, dev, "(whcrc %p)\n", whcrc); | ||
174 | |||
175 | le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR); | ||
176 | |||
177 | spin_lock(&whcrc->irq_lock); | ||
178 | urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE; | ||
179 | le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD); | ||
180 | spin_unlock(&whcrc->irq_lock); | ||
181 | |||
182 | d_fnend(4, dev, "(whcrc %p) = void\n", whcrc); | ||
183 | } | ||
184 | |||
185 | static void whcrc_event_work(struct work_struct *work) | ||
186 | { | ||
187 | struct whcrc *whcrc = container_of(work, struct whcrc, event_work); | ||
188 | struct device *dev = &whcrc->umc_dev->dev; | ||
189 | size_t size; | ||
190 | u64 urcevtaddr; | ||
191 | |||
192 | urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR); | ||
193 | size = urcevtaddr & URCEVTADDR_OFFSET_MASK; | ||
194 | |||
195 | d_printf(3, dev, "received %zu octet event\n", size); | ||
196 | d_dump(4, dev, whcrc->evt_buf, size > 32 ? 32 : size); | ||
197 | |||
198 | uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size); | ||
199 | whcrc_enable_events(whcrc); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Catch interrupts? | ||
204 | * | ||
205 | * We ack inmediately (and expect the hw to do the right thing and | ||
206 | * raise another IRQ if things have changed :) | ||
207 | */ | ||
208 | static | ||
209 | irqreturn_t whcrc_irq_cb(int irq, void *_whcrc) | ||
210 | { | ||
211 | struct whcrc *whcrc = _whcrc; | ||
212 | struct device *dev = &whcrc->umc_dev->dev; | ||
213 | u32 urcsts; | ||
214 | |||
215 | urcsts = le_readl(whcrc->rc_base + URCSTS); | ||
216 | if (!(urcsts & URCSTS_INT_MASK)) | ||
217 | return IRQ_NONE; | ||
218 | le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS); | ||
219 | |||
220 | d_printf(4, dev, "acked 0x%08x, urcsts 0x%08x\n", | ||
221 | le_readl(whcrc->rc_base + URCSTS), urcsts); | ||
222 | |||
223 | if (urcsts & URCSTS_HSE) { | ||
224 | dev_err(dev, "host system error -- hardware halted\n"); | ||
225 | /* FIXME: do something sensible here */ | ||
226 | goto out; | ||
227 | } | ||
228 | if (urcsts & URCSTS_ER) { | ||
229 | d_printf(3, dev, "ER: event ready\n"); | ||
230 | schedule_work(&whcrc->event_work); | ||
231 | } | ||
232 | if (urcsts & URCSTS_RCI) { | ||
233 | d_printf(3, dev, "RCI: ready to execute another command\n"); | ||
234 | wake_up_all(&whcrc->cmd_wq); | ||
235 | } | ||
236 | out: | ||
237 | return IRQ_HANDLED; | ||
238 | } | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Initialize a UMC RC interface: map regions, get (shared) IRQ | ||
243 | */ | ||
244 | static | ||
245 | int whcrc_setup_rc_umc(struct whcrc *whcrc) | ||
246 | { | ||
247 | int result = 0; | ||
248 | struct device *dev = &whcrc->umc_dev->dev; | ||
249 | struct umc_dev *umc_dev = whcrc->umc_dev; | ||
250 | |||
251 | whcrc->area = umc_dev->resource.start; | ||
252 | whcrc->rc_len = umc_dev->resource.end - umc_dev->resource.start + 1; | ||
253 | result = -EBUSY; | ||
254 | if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) | ||
255 | == NULL) { | ||
256 | dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n", | ||
257 | whcrc->rc_len, whcrc->area, result); | ||
258 | goto error_request_region; | ||
259 | } | ||
260 | |||
261 | whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len); | ||
262 | if (whcrc->rc_base == NULL) { | ||
263 | dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n", | ||
264 | whcrc->rc_len, whcrc->area, result); | ||
265 | goto error_ioremap_nocache; | ||
266 | } | ||
267 | |||
268 | result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED, | ||
269 | KBUILD_MODNAME, whcrc); | ||
270 | if (result < 0) { | ||
271 | dev_err(dev, "can't allocate IRQ %d: %d\n", | ||
272 | umc_dev->irq, result); | ||
273 | goto error_request_irq; | ||
274 | } | ||
275 | |||
276 | result = -ENOMEM; | ||
277 | whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE, | ||
278 | &whcrc->cmd_dma_buf, GFP_KERNEL); | ||
279 | if (whcrc->cmd_buf == NULL) { | ||
280 | dev_err(dev, "Can't allocate cmd transfer buffer\n"); | ||
281 | goto error_cmd_buffer; | ||
282 | } | ||
283 | |||
284 | whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE, | ||
285 | &whcrc->evt_dma_buf, GFP_KERNEL); | ||
286 | if (whcrc->evt_buf == NULL) { | ||
287 | dev_err(dev, "Can't allocate evt transfer buffer\n"); | ||
288 | goto error_evt_buffer; | ||
289 | } | ||
290 | d_printf(3, dev, "UWB RC Interface: %zu bytes at 0x%p, irq %u\n", | ||
291 | whcrc->rc_len, whcrc->rc_base, umc_dev->irq); | ||
292 | return 0; | ||
293 | |||
294 | error_evt_buffer: | ||
295 | dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf, | ||
296 | whcrc->cmd_dma_buf); | ||
297 | error_cmd_buffer: | ||
298 | free_irq(umc_dev->irq, whcrc); | ||
299 | error_request_irq: | ||
300 | iounmap(whcrc->rc_base); | ||
301 | error_ioremap_nocache: | ||
302 | release_mem_region(whcrc->area, whcrc->rc_len); | ||
303 | error_request_region: | ||
304 | return result; | ||
305 | } | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Release RC's UMC resources | ||
310 | */ | ||
311 | static | ||
312 | void whcrc_release_rc_umc(struct whcrc *whcrc) | ||
313 | { | ||
314 | struct umc_dev *umc_dev = whcrc->umc_dev; | ||
315 | |||
316 | dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf, | ||
317 | whcrc->evt_dma_buf); | ||
318 | dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf, | ||
319 | whcrc->cmd_dma_buf); | ||
320 | free_irq(umc_dev->irq, whcrc); | ||
321 | iounmap(whcrc->rc_base); | ||
322 | release_mem_region(whcrc->area, whcrc->rc_len); | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * whcrc_start_rc - start a WHCI radio controller | ||
328 | * @whcrc: the radio controller to start | ||
329 | * | ||
330 | * Reset the UMC device, start the radio controller, enable events and | ||
331 | * finally enable interrupts. | ||
332 | */ | ||
333 | static int whcrc_start_rc(struct uwb_rc *rc) | ||
334 | { | ||
335 | struct whcrc *whcrc = rc->priv; | ||
336 | int result = 0; | ||
337 | struct device *dev = &whcrc->umc_dev->dev; | ||
338 | unsigned long start, duration; | ||
339 | |||
340 | /* Reset the thing */ | ||
341 | le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD); | ||
342 | if (d_test(3)) | ||
343 | start = jiffies; | ||
344 | if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0, | ||
345 | 5000, "device to reset at init") < 0) { | ||
346 | result = -EBUSY; | ||
347 | goto error; | ||
348 | } else if (d_test(3)) { | ||
349 | duration = jiffies - start; | ||
350 | if (duration > msecs_to_jiffies(40)) | ||
351 | dev_err(dev, "Device took %ums to " | ||
352 | "reset. MAX expected: 40ms\n", | ||
353 | jiffies_to_msecs(duration)); | ||
354 | } | ||
355 | |||
356 | /* Set the event buffer, start the controller (enable IRQs later) */ | ||
357 | le_writel(0, whcrc->rc_base + URCINTR); | ||
358 | le_writel(URCCMD_RS, whcrc->rc_base + URCCMD); | ||
359 | result = -ETIMEDOUT; | ||
360 | if (d_test(3)) | ||
361 | start = jiffies; | ||
362 | if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0, | ||
363 | 5000, "device to start") < 0) | ||
364 | goto error; | ||
365 | if (d_test(3)) { | ||
366 | duration = jiffies - start; | ||
367 | if (duration > msecs_to_jiffies(40)) | ||
368 | dev_err(dev, "Device took %ums to start. " | ||
369 | "MAX expected: 40ms\n", | ||
370 | jiffies_to_msecs(duration)); | ||
371 | } | ||
372 | whcrc_enable_events(whcrc); | ||
373 | result = 0; | ||
374 | le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR); | ||
375 | error: | ||
376 | return result; | ||
377 | } | ||
378 | |||
379 | |||
380 | /** | ||
381 | * whcrc_stop_rc - stop a WHCI radio controller | ||
382 | * @whcrc: the radio controller to stop | ||
383 | * | ||
384 | * Disable interrupts and cancel any pending event processing work | ||
385 | * before clearing the Run/Stop bit. | ||
386 | */ | ||
387 | static | ||
388 | void whcrc_stop_rc(struct uwb_rc *rc) | ||
389 | { | ||
390 | struct whcrc *whcrc = rc->priv; | ||
391 | struct umc_dev *umc_dev = whcrc->umc_dev; | ||
392 | |||
393 | le_writel(0, whcrc->rc_base + URCINTR); | ||
394 | cancel_work_sync(&whcrc->event_work); | ||
395 | |||
396 | le_writel(0, whcrc->rc_base + URCCMD); | ||
397 | whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS, | ||
398 | URCSTS_HALTED, 0, 40, "URCSTS.HALTED"); | ||
399 | } | ||
400 | |||
401 | static void whcrc_init(struct whcrc *whcrc) | ||
402 | { | ||
403 | spin_lock_init(&whcrc->irq_lock); | ||
404 | init_waitqueue_head(&whcrc->cmd_wq); | ||
405 | INIT_WORK(&whcrc->event_work, whcrc_event_work); | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * Initialize the radio controller. | ||
410 | * | ||
411 | * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the | ||
412 | * IRQ handler we use that to determine if the hw is ready to | ||
413 | * handle events. Looks like a race condition, but it really is | ||
414 | * not. | ||
415 | */ | ||
416 | static | ||
417 | int whcrc_probe(struct umc_dev *umc_dev) | ||
418 | { | ||
419 | int result; | ||
420 | struct uwb_rc *uwb_rc; | ||
421 | struct whcrc *whcrc; | ||
422 | struct device *dev = &umc_dev->dev; | ||
423 | |||
424 | d_fnstart(3, dev, "(umc_dev %p)\n", umc_dev); | ||
425 | result = -ENOMEM; | ||
426 | uwb_rc = uwb_rc_alloc(); | ||
427 | if (uwb_rc == NULL) { | ||
428 | dev_err(dev, "unable to allocate RC instance\n"); | ||
429 | goto error_rc_alloc; | ||
430 | } | ||
431 | whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL); | ||
432 | if (whcrc == NULL) { | ||
433 | dev_err(dev, "unable to allocate WHC-RC instance\n"); | ||
434 | goto error_alloc; | ||
435 | } | ||
436 | whcrc_init(whcrc); | ||
437 | whcrc->umc_dev = umc_dev; | ||
438 | |||
439 | result = whcrc_setup_rc_umc(whcrc); | ||
440 | if (result < 0) { | ||
441 | dev_err(dev, "Can't setup RC UMC interface: %d\n", result); | ||
442 | goto error_setup_rc_umc; | ||
443 | } | ||
444 | whcrc->uwb_rc = uwb_rc; | ||
445 | |||
446 | uwb_rc->owner = THIS_MODULE; | ||
447 | uwb_rc->cmd = whcrc_cmd; | ||
448 | uwb_rc->reset = whcrc_reset; | ||
449 | uwb_rc->start = whcrc_start_rc; | ||
450 | uwb_rc->stop = whcrc_stop_rc; | ||
451 | |||
452 | result = uwb_rc_add(uwb_rc, dev, whcrc); | ||
453 | if (result < 0) | ||
454 | goto error_rc_add; | ||
455 | umc_set_drvdata(umc_dev, whcrc); | ||
456 | d_fnend(3, dev, "(umc_dev %p) = 0\n", umc_dev); | ||
457 | return 0; | ||
458 | |||
459 | error_rc_add: | ||
460 | whcrc_release_rc_umc(whcrc); | ||
461 | error_setup_rc_umc: | ||
462 | kfree(whcrc); | ||
463 | error_alloc: | ||
464 | uwb_rc_put(uwb_rc); | ||
465 | error_rc_alloc: | ||
466 | d_fnend(3, dev, "(umc_dev %p) = %d\n", umc_dev, result); | ||
467 | return result; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * Clean up the radio control resources | ||
472 | * | ||
473 | * When we up the command semaphore, everybody possibly held trying to | ||
474 | * execute a command should be granted entry and then they'll see the | ||
475 | * host is quiescing and up it (so it will chain to the next waiter). | ||
476 | * This should not happen (in any case), as we can only remove when | ||
477 | * there are no handles open... | ||
478 | */ | ||
479 | static void whcrc_remove(struct umc_dev *umc_dev) | ||
480 | { | ||
481 | struct whcrc *whcrc = umc_get_drvdata(umc_dev); | ||
482 | struct uwb_rc *uwb_rc = whcrc->uwb_rc; | ||
483 | |||
484 | umc_set_drvdata(umc_dev, NULL); | ||
485 | uwb_rc_rm(uwb_rc); | ||
486 | whcrc_release_rc_umc(whcrc); | ||
487 | kfree(whcrc); | ||
488 | uwb_rc_put(uwb_rc); | ||
489 | d_printf(1, &umc_dev->dev, "freed whcrc %p\n", whcrc); | ||
490 | } | ||
491 | |||
492 | /* PCI device ID's that we handle [so it gets loaded] */ | ||
493 | static struct pci_device_id whcrc_id_table[] = { | ||
494 | { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, | ||
495 | { /* empty last entry */ } | ||
496 | }; | ||
497 | MODULE_DEVICE_TABLE(pci, whcrc_id_table); | ||
498 | |||
499 | static struct umc_driver whcrc_driver = { | ||
500 | .name = "whc-rc", | ||
501 | .cap_id = UMC_CAP_ID_WHCI_RC, | ||
502 | .probe = whcrc_probe, | ||
503 | .remove = whcrc_remove, | ||
504 | }; | ||
505 | |||
506 | static int __init whcrc_driver_init(void) | ||
507 | { | ||
508 | return umc_driver_register(&whcrc_driver); | ||
509 | } | ||
510 | module_init(whcrc_driver_init); | ||
511 | |||
512 | static void __exit whcrc_driver_exit(void) | ||
513 | { | ||
514 | umc_driver_unregister(&whcrc_driver); | ||
515 | } | ||
516 | module_exit(whcrc_driver_exit); | ||
517 | |||
518 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
519 | MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver"); | ||
520 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c new file mode 100644 index 000000000000..3df2388f908f --- /dev/null +++ b/drivers/uwb/whci.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * WHCI UWB Multi-interface Controller enumerator. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This file is released under the GNU GPL v2. | ||
7 | */ | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/pci.h> | ||
11 | #include <linux/dma-mapping.h> | ||
12 | #include <linux/uwb/whci.h> | ||
13 | #include <linux/uwb/umc.h> | ||
14 | |||
15 | struct whci_card { | ||
16 | struct pci_dev *pci; | ||
17 | void __iomem *uwbbase; | ||
18 | u8 n_caps; | ||
19 | struct umc_dev *devs[0]; | ||
20 | }; | ||
21 | |||
22 | |||
23 | /* Fix faulty HW :( */ | ||
24 | static | ||
25 | u64 whci_capdata_quirks(struct whci_card *card, u64 capdata) | ||
26 | { | ||
27 | u64 capdata_orig = capdata; | ||
28 | struct pci_dev *pci_dev = card->pci; | ||
29 | if (pci_dev->vendor == PCI_VENDOR_ID_INTEL | ||
30 | && (pci_dev->device == 0x0c3b || pci_dev->device == 0004) | ||
31 | && pci_dev->class == 0x0d1010) { | ||
32 | switch (UWBCAPDATA_TO_CAP_ID(capdata)) { | ||
33 | /* WLP capability has 0x100 bytes of aperture */ | ||
34 | case 0x80: | ||
35 | capdata |= 0x40 << 8; break; | ||
36 | /* WUSB capability has 0x80 bytes of aperture | ||
37 | * and ID is 1 */ | ||
38 | case 0x02: | ||
39 | capdata &= ~0xffff; | ||
40 | capdata |= 0x2001; | ||
41 | break; | ||
42 | } | ||
43 | } | ||
44 | if (capdata_orig != capdata) | ||
45 | dev_warn(&pci_dev->dev, | ||
46 | "PCI v%04x d%04x c%06x#%02x: " | ||
47 | "corrected capdata from %016Lx to %016Lx\n", | ||
48 | pci_dev->vendor, pci_dev->device, pci_dev->class, | ||
49 | (unsigned)UWBCAPDATA_TO_CAP_ID(capdata), | ||
50 | (unsigned long long)capdata_orig, | ||
51 | (unsigned long long)capdata); | ||
52 | return capdata; | ||
53 | } | ||
54 | |||
55 | |||
56 | /** | ||
57 | * whci_wait_for - wait for a WHCI register to be set | ||
58 | * | ||
59 | * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'. | ||
60 | */ | ||
61 | int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result, | ||
62 | unsigned long max_ms, const char *tag) | ||
63 | { | ||
64 | unsigned t = 0; | ||
65 | u32 val; | ||
66 | for (;;) { | ||
67 | val = le_readl(reg); | ||
68 | if ((val & mask) == result) | ||
69 | break; | ||
70 | msleep(10); | ||
71 | if (t >= max_ms) { | ||
72 | dev_err(dev, "timed out waiting for %s ", tag); | ||
73 | return -ETIMEDOUT; | ||
74 | } | ||
75 | t += 10; | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(whci_wait_for); | ||
80 | |||
81 | |||
82 | /* | ||
83 | * NOTE: the capinfo and capdata registers are slightly different | ||
84 | * (size and cap-id fields). So for cap #0, we need to fill | ||
85 | * in. Size comes from the size of the register block | ||
86 | * (statically calculated); cap_id comes from nowhere, we use | ||
87 | * zero, that is reserved, for the radio controller, because | ||
88 | * none was defined at the spec level. | ||
89 | */ | ||
90 | static int whci_add_cap(struct whci_card *card, int n) | ||
91 | { | ||
92 | struct umc_dev *umc; | ||
93 | u64 capdata; | ||
94 | int bar, err; | ||
95 | |||
96 | umc = umc_device_create(&card->pci->dev, n); | ||
97 | if (umc == NULL) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | capdata = le_readq(card->uwbbase + UWBCAPDATA(n)); | ||
101 | |||
102 | bar = UWBCAPDATA_TO_BAR(capdata) << 1; | ||
103 | |||
104 | capdata = whci_capdata_quirks(card, capdata); | ||
105 | /* Capability 0 is the radio controller. It's size is 32 | ||
106 | * bytes (WHCI0.95[2.3, T2-9]). */ | ||
107 | umc->version = UWBCAPDATA_TO_VERSION(capdata); | ||
108 | umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata); | ||
109 | umc->bar = bar; | ||
110 | umc->resource.start = pci_resource_start(card->pci, bar) | ||
111 | + UWBCAPDATA_TO_OFFSET(capdata); | ||
112 | umc->resource.end = umc->resource.start | ||
113 | + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1; | ||
114 | umc->resource.name = umc->dev.bus_id; | ||
115 | umc->resource.flags = card->pci->resource[bar].flags; | ||
116 | umc->resource.parent = &card->pci->resource[bar]; | ||
117 | umc->irq = card->pci->irq; | ||
118 | |||
119 | err = umc_device_register(umc); | ||
120 | if (err < 0) | ||
121 | goto error; | ||
122 | card->devs[n] = umc; | ||
123 | return 0; | ||
124 | |||
125 | error: | ||
126 | kfree(umc); | ||
127 | return err; | ||
128 | } | ||
129 | |||
130 | static void whci_del_cap(struct whci_card *card, int n) | ||
131 | { | ||
132 | struct umc_dev *umc = card->devs[n]; | ||
133 | |||
134 | if (umc != NULL) | ||
135 | umc_device_unregister(umc); | ||
136 | } | ||
137 | |||
138 | static int whci_n_caps(struct pci_dev *pci) | ||
139 | { | ||
140 | void __iomem *uwbbase; | ||
141 | u64 capinfo; | ||
142 | |||
143 | uwbbase = pci_iomap(pci, 0, 8); | ||
144 | if (!uwbbase) | ||
145 | return -ENOMEM; | ||
146 | capinfo = le_readq(uwbbase + UWBCAPINFO); | ||
147 | pci_iounmap(pci, uwbbase); | ||
148 | |||
149 | return UWBCAPINFO_TO_N_CAPS(capinfo); | ||
150 | } | ||
151 | |||
152 | static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id) | ||
153 | { | ||
154 | struct whci_card *card; | ||
155 | int err, n_caps, n; | ||
156 | |||
157 | err = pci_enable_device(pci); | ||
158 | if (err < 0) | ||
159 | goto error; | ||
160 | pci_enable_msi(pci); | ||
161 | pci_set_master(pci); | ||
162 | err = -ENXIO; | ||
163 | if (!pci_set_dma_mask(pci, DMA_64BIT_MASK)) | ||
164 | pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK); | ||
165 | else if (!pci_set_dma_mask(pci, DMA_32BIT_MASK)) | ||
166 | pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK); | ||
167 | else | ||
168 | goto error_dma; | ||
169 | |||
170 | err = n_caps = whci_n_caps(pci); | ||
171 | if (n_caps < 0) | ||
172 | goto error_ncaps; | ||
173 | |||
174 | err = -ENOMEM; | ||
175 | card = kzalloc(sizeof(struct whci_card) | ||
176 | + sizeof(struct whci_dev *) * (n_caps + 1), | ||
177 | GFP_KERNEL); | ||
178 | if (card == NULL) | ||
179 | goto error_kzalloc; | ||
180 | card->pci = pci; | ||
181 | card->n_caps = n_caps; | ||
182 | |||
183 | err = -EBUSY; | ||
184 | if (!request_mem_region(pci_resource_start(pci, 0), | ||
185 | UWBCAPDATA_SIZE(card->n_caps), | ||
186 | "whci (capability data)")) | ||
187 | goto error_request_memregion; | ||
188 | err = -ENOMEM; | ||
189 | card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps)); | ||
190 | if (!card->uwbbase) | ||
191 | goto error_iomap; | ||
192 | |||
193 | /* Add each capability. */ | ||
194 | for (n = 0; n <= card->n_caps; n++) { | ||
195 | err = whci_add_cap(card, n); | ||
196 | if (err < 0 && n == 0) { | ||
197 | dev_err(&pci->dev, "cannot bind UWB radio controller:" | ||
198 | " %d\n", err); | ||
199 | goto error_bind; | ||
200 | } | ||
201 | if (err < 0) | ||
202 | dev_warn(&pci->dev, "warning: cannot bind capability " | ||
203 | "#%u: %d\n", n, err); | ||
204 | } | ||
205 | pci_set_drvdata(pci, card); | ||
206 | return 0; | ||
207 | |||
208 | error_bind: | ||
209 | pci_iounmap(pci, card->uwbbase); | ||
210 | error_iomap: | ||
211 | release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); | ||
212 | error_request_memregion: | ||
213 | kfree(card); | ||
214 | error_kzalloc: | ||
215 | error_ncaps: | ||
216 | error_dma: | ||
217 | pci_disable_msi(pci); | ||
218 | pci_disable_device(pci); | ||
219 | error: | ||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static void whci_remove(struct pci_dev *pci) | ||
224 | { | ||
225 | struct whci_card *card = pci_get_drvdata(pci); | ||
226 | int n; | ||
227 | |||
228 | pci_set_drvdata(pci, NULL); | ||
229 | /* Unregister each capability in reverse (so the master device | ||
230 | * is unregistered last). */ | ||
231 | for (n = card->n_caps; n >= 0 ; n--) | ||
232 | whci_del_cap(card, n); | ||
233 | pci_iounmap(pci, card->uwbbase); | ||
234 | release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); | ||
235 | kfree(card); | ||
236 | pci_disable_msi(pci); | ||
237 | pci_disable_device(pci); | ||
238 | } | ||
239 | |||
240 | static struct pci_device_id whci_id_table[] = { | ||
241 | { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, | ||
242 | { 0 }, | ||
243 | }; | ||
244 | MODULE_DEVICE_TABLE(pci, whci_id_table); | ||
245 | |||
246 | |||
247 | static struct pci_driver whci_driver = { | ||
248 | .name = "whci", | ||
249 | .id_table = whci_id_table, | ||
250 | .probe = whci_probe, | ||
251 | .remove = whci_remove, | ||
252 | }; | ||
253 | |||
254 | static int __init whci_init(void) | ||
255 | { | ||
256 | return pci_register_driver(&whci_driver); | ||
257 | } | ||
258 | |||
259 | static void __exit whci_exit(void) | ||
260 | { | ||
261 | pci_unregister_driver(&whci_driver); | ||
262 | } | ||
263 | |||
264 | module_init(whci_init); | ||
265 | module_exit(whci_exit); | ||
266 | |||
267 | MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator"); | ||
268 | MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); | ||
269 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile new file mode 100644 index 000000000000..c72c11db5b1b --- /dev/null +++ b/drivers/uwb/wlp/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | obj-$(CONFIG_UWB_WLP) := wlp.o | ||
2 | |||
3 | wlp-objs := \ | ||
4 | driver.o \ | ||
5 | eda.o \ | ||
6 | messages.o \ | ||
7 | sysfs.o \ | ||
8 | txrx.o \ | ||
9 | wlp-lc.o \ | ||
10 | wss-lc.o | ||
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c new file mode 100644 index 000000000000..cb8d699b6a67 --- /dev/null +++ b/drivers/uwb/wlp/driver.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2007 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Life cycle of WLP substack | ||
23 | * | ||
24 | * FIXME: Docs | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | |||
29 | static int __init wlp_subsys_init(void) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | module_init(wlp_subsys_init); | ||
34 | |||
35 | static void __exit wlp_subsys_exit(void) | ||
36 | { | ||
37 | return; | ||
38 | } | ||
39 | module_exit(wlp_subsys_exit); | ||
40 | |||
41 | MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>"); | ||
42 | MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)"); | ||
43 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c new file mode 100644 index 000000000000..cdfe8dfc4340 --- /dev/null +++ b/drivers/uwb/wlp/eda.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Ethernet to device address cache | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * We need to be able to map ethernet addresses to device addresses | ||
24 | * and back because there is not explicit relationship between the eth | ||
25 | * addresses used in the ETH frames and the device addresses (no, it | ||
26 | * would not have been simpler to force as ETH address the MBOA MAC | ||
27 | * address...no, not at all :). | ||
28 | * | ||
29 | * A device has one MBOA MAC address and one device address. It is possible | ||
30 | * for a device to have more than one virtual MAC address (although a | ||
31 | * virtual address can be the same as the MBOA MAC address). The device | ||
32 | * address is guaranteed to be unique among the devices in the extended | ||
33 | * beacon group (see ECMA 17.1.1). We thus use the device address as index | ||
34 | * to this cache. We do allow searching based on virtual address as this | ||
35 | * is how Ethernet frames will be addressed. | ||
36 | * | ||
37 | * We need to support virtual EUI-48. Although, right now the virtual | ||
38 | * EUI-48 will always be the same as the MAC SAP address. The EDA cache | ||
39 | * entry thus contains a MAC SAP address as well as the virtual address | ||
40 | * (used to map the network stack address to a neighbor). When we move | ||
41 | * to support more than one virtual MAC on a host then this organization | ||
42 | * will have to change. Perhaps a neighbor has a list of WSSs, each with a | ||
43 | * tag and virtual EUI-48. | ||
44 | * | ||
45 | * On data transmission | ||
46 | * it is used to determine if the neighbor is connected and what WSS it | ||
47 | * belongs to. With this we know what tag to add to the WLP frame. Storing | ||
48 | * the WSS in the EDA cache may be overkill because we only support one | ||
49 | * WSS. Hopefully we will support more than one WSS at some point. | ||
50 | * On data reception it is used to determine the WSS based on | ||
51 | * the tag and address of the transmitting neighbor. | ||
52 | */ | ||
53 | |||
54 | #define D_LOCAL 5 | ||
55 | #include <linux/netdevice.h> | ||
56 | #include <linux/uwb/debug.h> | ||
57 | #include <linux/etherdevice.h> | ||
58 | #include <linux/wlp.h> | ||
59 | #include "wlp-internal.h" | ||
60 | |||
61 | |||
62 | /* FIXME: cache is not purged, only on device close */ | ||
63 | |||
64 | /* FIXME: does not scale, change to dynamic array */ | ||
65 | |||
66 | /* | ||
67 | * Initialize the EDA cache | ||
68 | * | ||
69 | * @returns 0 if ok, < 0 errno code on error | ||
70 | * | ||
71 | * Call when the interface is being brought up | ||
72 | * | ||
73 | * NOTE: Keep it as a separate function as the implementation will | ||
74 | * change and be more complex. | ||
75 | */ | ||
76 | void wlp_eda_init(struct wlp_eda *eda) | ||
77 | { | ||
78 | INIT_LIST_HEAD(&eda->cache); | ||
79 | spin_lock_init(&eda->lock); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Release the EDA cache | ||
84 | * | ||
85 | * @returns 0 if ok, < 0 errno code on error | ||
86 | * | ||
87 | * Called when the interface is brought down | ||
88 | */ | ||
89 | void wlp_eda_release(struct wlp_eda *eda) | ||
90 | { | ||
91 | unsigned long flags; | ||
92 | struct wlp_eda_node *itr, *next; | ||
93 | |||
94 | spin_lock_irqsave(&eda->lock, flags); | ||
95 | list_for_each_entry_safe(itr, next, &eda->cache, list_node) { | ||
96 | list_del(&itr->list_node); | ||
97 | kfree(itr); | ||
98 | } | ||
99 | spin_unlock_irqrestore(&eda->lock, flags); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Add an address mapping | ||
104 | * | ||
105 | * @returns 0 if ok, < 0 errno code on error | ||
106 | * | ||
107 | * An address mapping is initially created when the neighbor device is seen | ||
108 | * for the first time (it is "onair"). At this time the neighbor is not | ||
109 | * connected or associated with a WSS so we only populate the Ethernet and | ||
110 | * Device address fields. | ||
111 | * | ||
112 | */ | ||
113 | int wlp_eda_create_node(struct wlp_eda *eda, | ||
114 | const unsigned char eth_addr[ETH_ALEN], | ||
115 | const struct uwb_dev_addr *dev_addr) | ||
116 | { | ||
117 | int result = 0; | ||
118 | struct wlp_eda_node *itr; | ||
119 | unsigned long flags; | ||
120 | |||
121 | BUG_ON(dev_addr == NULL || eth_addr == NULL); | ||
122 | spin_lock_irqsave(&eda->lock, flags); | ||
123 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
124 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
125 | printk(KERN_ERR "EDA cache already contains entry " | ||
126 | "for neighbor %02x:%02x\n", | ||
127 | dev_addr->data[1], dev_addr->data[0]); | ||
128 | result = -EEXIST; | ||
129 | goto out_unlock; | ||
130 | } | ||
131 | } | ||
132 | itr = kzalloc(sizeof(*itr), GFP_ATOMIC); | ||
133 | if (itr != NULL) { | ||
134 | memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr)); | ||
135 | itr->dev_addr = *dev_addr; | ||
136 | list_add(&itr->list_node, &eda->cache); | ||
137 | } else | ||
138 | result = -ENOMEM; | ||
139 | out_unlock: | ||
140 | spin_unlock_irqrestore(&eda->lock, flags); | ||
141 | return result; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Remove entry from EDA cache | ||
146 | * | ||
147 | * This is done when the device goes off air. | ||
148 | */ | ||
149 | void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr) | ||
150 | { | ||
151 | struct wlp_eda_node *itr, *next; | ||
152 | unsigned long flags; | ||
153 | |||
154 | spin_lock_irqsave(&eda->lock, flags); | ||
155 | list_for_each_entry_safe(itr, next, &eda->cache, list_node) { | ||
156 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
157 | list_del(&itr->list_node); | ||
158 | kfree(itr); | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | spin_unlock_irqrestore(&eda->lock, flags); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Update an address mapping | ||
167 | * | ||
168 | * @returns 0 if ok, < 0 errno code on error | ||
169 | */ | ||
170 | int wlp_eda_update_node(struct wlp_eda *eda, | ||
171 | const struct uwb_dev_addr *dev_addr, | ||
172 | struct wlp_wss *wss, | ||
173 | const unsigned char virt_addr[ETH_ALEN], | ||
174 | const u8 tag, const enum wlp_wss_connect state) | ||
175 | { | ||
176 | int result = -ENOENT; | ||
177 | struct wlp_eda_node *itr; | ||
178 | unsigned long flags; | ||
179 | |||
180 | spin_lock_irqsave(&eda->lock, flags); | ||
181 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
182 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
183 | /* Found it, update it */ | ||
184 | itr->wss = wss; | ||
185 | memcpy(itr->virt_addr, virt_addr, | ||
186 | sizeof(itr->virt_addr)); | ||
187 | itr->tag = tag; | ||
188 | itr->state = state; | ||
189 | result = 0; | ||
190 | goto out_unlock; | ||
191 | } | ||
192 | } | ||
193 | /* Not found */ | ||
194 | out_unlock: | ||
195 | spin_unlock_irqrestore(&eda->lock, flags); | ||
196 | return result; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Update only state field of an address mapping | ||
201 | * | ||
202 | * @returns 0 if ok, < 0 errno code on error | ||
203 | */ | ||
204 | int wlp_eda_update_node_state(struct wlp_eda *eda, | ||
205 | const struct uwb_dev_addr *dev_addr, | ||
206 | const enum wlp_wss_connect state) | ||
207 | { | ||
208 | int result = -ENOENT; | ||
209 | struct wlp_eda_node *itr; | ||
210 | unsigned long flags; | ||
211 | |||
212 | spin_lock_irqsave(&eda->lock, flags); | ||
213 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
214 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
215 | /* Found it, update it */ | ||
216 | itr->state = state; | ||
217 | result = 0; | ||
218 | goto out_unlock; | ||
219 | } | ||
220 | } | ||
221 | /* Not found */ | ||
222 | out_unlock: | ||
223 | spin_unlock_irqrestore(&eda->lock, flags); | ||
224 | return result; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * Return contents of EDA cache entry | ||
229 | * | ||
230 | * @dev_addr: index to EDA cache | ||
231 | * @eda_entry: pointer to where contents of EDA cache will be copied | ||
232 | */ | ||
233 | int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr, | ||
234 | struct wlp_eda_node *eda_entry) | ||
235 | { | ||
236 | int result = -ENOENT; | ||
237 | struct wlp_eda_node *itr; | ||
238 | unsigned long flags; | ||
239 | |||
240 | spin_lock_irqsave(&eda->lock, flags); | ||
241 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
242 | if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) { | ||
243 | *eda_entry = *itr; | ||
244 | result = 0; | ||
245 | goto out_unlock; | ||
246 | } | ||
247 | } | ||
248 | /* Not found */ | ||
249 | out_unlock: | ||
250 | spin_unlock_irqrestore(&eda->lock, flags); | ||
251 | return result; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Execute function for every element in the cache | ||
256 | * | ||
257 | * @function: function to execute on element of cache (must be atomic) | ||
258 | * @priv: private data of function | ||
259 | * @returns: result of first function that failed, or last function | ||
260 | * executed if no function failed. | ||
261 | * | ||
262 | * Stop executing when function returns error for any element in cache. | ||
263 | * | ||
264 | * IMPORTANT: We are using a spinlock here: the function executed on each | ||
265 | * element has to be atomic. | ||
266 | */ | ||
267 | int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function, | ||
268 | void *priv) | ||
269 | { | ||
270 | int result = 0; | ||
271 | struct wlp *wlp = container_of(eda, struct wlp, eda); | ||
272 | struct wlp_eda_node *entry; | ||
273 | unsigned long flags; | ||
274 | |||
275 | spin_lock_irqsave(&eda->lock, flags); | ||
276 | list_for_each_entry(entry, &eda->cache, list_node) { | ||
277 | result = (*function)(wlp, entry, priv); | ||
278 | if (result < 0) | ||
279 | break; | ||
280 | } | ||
281 | spin_unlock_irqrestore(&eda->lock, flags); | ||
282 | return result; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Execute function for single element in the cache (return dev addr) | ||
287 | * | ||
288 | * @virt_addr: index into EDA cache used to determine which element to | ||
289 | * execute the function on | ||
290 | * @dev_addr: device address of element in cache will be returned using | ||
291 | * @dev_addr | ||
292 | * @function: function to execute on element of cache (must be atomic) | ||
293 | * @priv: private data of function | ||
294 | * @returns: result of function | ||
295 | * | ||
296 | * IMPORTANT: We are using a spinlock here: the function executed on the | ||
297 | * element has to be atomic. | ||
298 | */ | ||
299 | int wlp_eda_for_virtual(struct wlp_eda *eda, | ||
300 | const unsigned char virt_addr[ETH_ALEN], | ||
301 | struct uwb_dev_addr *dev_addr, | ||
302 | wlp_eda_for_each_f function, | ||
303 | void *priv) | ||
304 | { | ||
305 | int result = 0; | ||
306 | struct wlp *wlp = container_of(eda, struct wlp, eda); | ||
307 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
308 | struct wlp_eda_node *itr; | ||
309 | unsigned long flags; | ||
310 | int found = 0; | ||
311 | |||
312 | spin_lock_irqsave(&eda->lock, flags); | ||
313 | list_for_each_entry(itr, &eda->cache, list_node) { | ||
314 | if (!memcmp(itr->virt_addr, virt_addr, | ||
315 | sizeof(itr->virt_addr))) { | ||
316 | d_printf(6, dev, "EDA: looking for " | ||
317 | "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x " | ||
318 | "wss %p tag 0x%02x state %u\n", | ||
319 | virt_addr[0], virt_addr[1], | ||
320 | virt_addr[2], virt_addr[3], | ||
321 | virt_addr[4], virt_addr[5], | ||
322 | itr->dev_addr.data[1], | ||
323 | itr->dev_addr.data[0], itr->wss, | ||
324 | itr->tag, itr->state); | ||
325 | result = (*function)(wlp, itr, priv); | ||
326 | *dev_addr = itr->dev_addr; | ||
327 | found = 1; | ||
328 | break; | ||
329 | } else | ||
330 | d_printf(6, dev, "EDA: looking for " | ||
331 | "%02x:%02x:%02x:%02x:%02x:%02x " | ||
332 | "against " | ||
333 | "%02x:%02x:%02x:%02x:%02x:%02x miss\n", | ||
334 | virt_addr[0], virt_addr[1], | ||
335 | virt_addr[2], virt_addr[3], | ||
336 | virt_addr[4], virt_addr[5], | ||
337 | itr->virt_addr[0], itr->virt_addr[1], | ||
338 | itr->virt_addr[2], itr->virt_addr[3], | ||
339 | itr->virt_addr[4], itr->virt_addr[5]); | ||
340 | } | ||
341 | if (!found) { | ||
342 | if (printk_ratelimit()) | ||
343 | dev_err(dev, "EDA: Eth addr %02x:%02x:%02x" | ||
344 | ":%02x:%02x:%02x not found.\n", | ||
345 | virt_addr[0], virt_addr[1], | ||
346 | virt_addr[2], virt_addr[3], | ||
347 | virt_addr[4], virt_addr[5]); | ||
348 | result = -ENODEV; | ||
349 | } | ||
350 | spin_unlock_irqrestore(&eda->lock, flags); | ||
351 | return result; | ||
352 | } | ||
353 | |||
354 | static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED", | ||
355 | "WLP_WSS_CONNECTED", | ||
356 | "WLP_WSS_CONNECT_FAILED", | ||
357 | }; | ||
358 | |||
359 | static const char *wlp_wss_connect_state_str(unsigned id) | ||
360 | { | ||
361 | if (id >= ARRAY_SIZE(__wlp_wss_connect_state)) | ||
362 | return "unknown WSS connection state"; | ||
363 | return __wlp_wss_connect_state[id]; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * View EDA cache from user space | ||
368 | * | ||
369 | * A debugging feature to give user visibility into the EDA cache. Also | ||
370 | * used to display members of WSS to user (called from wlp_wss_members_show()) | ||
371 | */ | ||
372 | ssize_t wlp_eda_show(struct wlp *wlp, char *buf) | ||
373 | { | ||
374 | ssize_t result = 0; | ||
375 | struct wlp_eda_node *entry; | ||
376 | unsigned long flags; | ||
377 | struct wlp_eda *eda = &wlp->eda; | ||
378 | spin_lock_irqsave(&eda->lock, flags); | ||
379 | result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr " | ||
380 | "tag state virt_addr\n"); | ||
381 | list_for_each_entry(entry, &eda->cache, list_node) { | ||
382 | result += scnprintf(buf + result, PAGE_SIZE - result, | ||
383 | "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x " | ||
384 | "%p 0x%02x %s " | ||
385 | "%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
386 | entry->eth_addr[0], entry->eth_addr[1], | ||
387 | entry->eth_addr[2], entry->eth_addr[3], | ||
388 | entry->eth_addr[4], entry->eth_addr[5], | ||
389 | entry->dev_addr.data[1], | ||
390 | entry->dev_addr.data[0], entry->wss, | ||
391 | entry->tag, | ||
392 | wlp_wss_connect_state_str(entry->state), | ||
393 | entry->virt_addr[0], entry->virt_addr[1], | ||
394 | entry->virt_addr[2], entry->virt_addr[3], | ||
395 | entry->virt_addr[4], entry->virt_addr[5]); | ||
396 | if (result >= PAGE_SIZE) | ||
397 | break; | ||
398 | } | ||
399 | spin_unlock_irqrestore(&eda->lock, flags); | ||
400 | return result; | ||
401 | } | ||
402 | EXPORT_SYMBOL_GPL(wlp_eda_show); | ||
403 | |||
404 | /* | ||
405 | * Add new EDA cache entry based on user input in sysfs | ||
406 | * | ||
407 | * Should only be used for debugging. | ||
408 | * | ||
409 | * The WSS is assumed to be the only WSS supported. This needs to be | ||
410 | * redesigned when we support more than one WSS. | ||
411 | */ | ||
412 | ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size) | ||
413 | { | ||
414 | ssize_t result; | ||
415 | struct wlp_eda *eda = &wlp->eda; | ||
416 | u8 eth_addr[6]; | ||
417 | struct uwb_dev_addr dev_addr; | ||
418 | u8 tag; | ||
419 | unsigned state; | ||
420 | |||
421 | result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx " | ||
422 | "%02hhx:%02hhx %02hhx %u\n", | ||
423 | ð_addr[0], ð_addr[1], | ||
424 | ð_addr[2], ð_addr[3], | ||
425 | ð_addr[4], ð_addr[5], | ||
426 | &dev_addr.data[1], &dev_addr.data[0], &tag, &state); | ||
427 | switch (result) { | ||
428 | case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */ | ||
429 | /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/ | ||
430 | result = -ENOSYS; | ||
431 | break; | ||
432 | case 10: | ||
433 | state = state >= 1 ? 1 : 0; | ||
434 | result = wlp_eda_create_node(eda, eth_addr, &dev_addr); | ||
435 | if (result < 0 && result != -EEXIST) | ||
436 | goto error; | ||
437 | /* Set virtual addr to be same as MAC */ | ||
438 | result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss, | ||
439 | eth_addr, tag, state); | ||
440 | if (result < 0) | ||
441 | goto error; | ||
442 | break; | ||
443 | default: /* bad format */ | ||
444 | result = -EINVAL; | ||
445 | } | ||
446 | error: | ||
447 | return result < 0 ? result : size; | ||
448 | } | ||
449 | EXPORT_SYMBOL_GPL(wlp_eda_store); | ||
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c new file mode 100644 index 000000000000..a64cb8241713 --- /dev/null +++ b/drivers/uwb/wlp/messages.c | |||
@@ -0,0 +1,1946 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Message construction and parsing | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/wlp.h> | ||
27 | #define D_LOCAL 6 | ||
28 | #include <linux/uwb/debug.h> | ||
29 | #include "wlp-internal.h" | ||
30 | |||
31 | static | ||
32 | const char *__wlp_assoc_frame[] = { | ||
33 | [WLP_ASSOC_D1] = "WLP_ASSOC_D1", | ||
34 | [WLP_ASSOC_D2] = "WLP_ASSOC_D2", | ||
35 | [WLP_ASSOC_M1] = "WLP_ASSOC_M1", | ||
36 | [WLP_ASSOC_M2] = "WLP_ASSOC_M2", | ||
37 | [WLP_ASSOC_M3] = "WLP_ASSOC_M3", | ||
38 | [WLP_ASSOC_M4] = "WLP_ASSOC_M4", | ||
39 | [WLP_ASSOC_M5] = "WLP_ASSOC_M5", | ||
40 | [WLP_ASSOC_M6] = "WLP_ASSOC_M6", | ||
41 | [WLP_ASSOC_M7] = "WLP_ASSOC_M7", | ||
42 | [WLP_ASSOC_M8] = "WLP_ASSOC_M8", | ||
43 | [WLP_ASSOC_F0] = "WLP_ASSOC_F0", | ||
44 | [WLP_ASSOC_E1] = "WLP_ASSOC_E1", | ||
45 | [WLP_ASSOC_E2] = "WLP_ASSOC_E2", | ||
46 | [WLP_ASSOC_C1] = "WLP_ASSOC_C1", | ||
47 | [WLP_ASSOC_C2] = "WLP_ASSOC_C2", | ||
48 | [WLP_ASSOC_C3] = "WLP_ASSOC_C3", | ||
49 | [WLP_ASSOC_C4] = "WLP_ASSOC_C4", | ||
50 | }; | ||
51 | |||
52 | static const char *wlp_assoc_frame_str(unsigned id) | ||
53 | { | ||
54 | if (id >= ARRAY_SIZE(__wlp_assoc_frame)) | ||
55 | return "unknown association frame"; | ||
56 | return __wlp_assoc_frame[id]; | ||
57 | } | ||
58 | |||
59 | static const char *__wlp_assc_error[] = { | ||
60 | "none", | ||
61 | "Authenticator Failure", | ||
62 | "Rogue activity suspected", | ||
63 | "Device busy", | ||
64 | "Setup Locked", | ||
65 | "Registrar not ready", | ||
66 | "Invalid WSS selection", | ||
67 | "Message timeout", | ||
68 | "Enrollment session timeout", | ||
69 | "Device password invalid", | ||
70 | "Unsupported version", | ||
71 | "Internal error", | ||
72 | "Undefined error", | ||
73 | "Numeric comparison failure", | ||
74 | "Waiting for user input", | ||
75 | }; | ||
76 | |||
77 | static const char *wlp_assc_error_str(unsigned id) | ||
78 | { | ||
79 | if (id >= ARRAY_SIZE(__wlp_assc_error)) | ||
80 | return "unknown WLP association error"; | ||
81 | return __wlp_assc_error[id]; | ||
82 | } | ||
83 | |||
84 | static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type, | ||
85 | size_t len) | ||
86 | { | ||
87 | hdr->type = cpu_to_le16(type); | ||
88 | hdr->length = cpu_to_le16(len); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Populate fields of a constant sized attribute | ||
93 | * | ||
94 | * @returns: total size of attribute including size of new value | ||
95 | * | ||
96 | * We have two instances of this function (wlp_pset and wlp_set): one takes | ||
97 | * the value as a parameter, the other takes a pointer to the value as | ||
98 | * parameter. They thus only differ in how the value is assigned to the | ||
99 | * attribute. | ||
100 | * | ||
101 | * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of | ||
102 | * sizeof(type) to be able to use this same code for the structures that | ||
103 | * contain 8bit enum values and be able to deal with pointer types. | ||
104 | */ | ||
105 | #define wlp_set(type, type_code, name) \ | ||
106 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ | ||
107 | { \ | ||
108 | d_fnstart(6, NULL, "(attribute %p)\n", attr); \ | ||
109 | wlp_set_attr_hdr(&attr->hdr, type_code, \ | ||
110 | sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ | ||
111 | attr->name = value; \ | ||
112 | d_dump(6, NULL, attr, sizeof(*attr)); \ | ||
113 | d_fnend(6, NULL, "(attribute %p)\n", attr); \ | ||
114 | return sizeof(*attr); \ | ||
115 | } | ||
116 | |||
117 | #define wlp_pset(type, type_code, name) \ | ||
118 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \ | ||
119 | { \ | ||
120 | d_fnstart(6, NULL, "(attribute %p)\n", attr); \ | ||
121 | wlp_set_attr_hdr(&attr->hdr, type_code, \ | ||
122 | sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \ | ||
123 | attr->name = *value; \ | ||
124 | d_dump(6, NULL, attr, sizeof(*attr)); \ | ||
125 | d_fnend(6, NULL, "(attribute %p)\n", attr); \ | ||
126 | return sizeof(*attr); \ | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * Populate fields of a variable attribute | ||
131 | * | ||
132 | * @returns: total size of attribute including size of new value | ||
133 | * | ||
134 | * Provided with a pointer to the memory area reserved for the | ||
135 | * attribute structure, the field is populated with the value. The | ||
136 | * reserved memory has to contain enough space for the value. | ||
137 | */ | ||
138 | #define wlp_vset(type, type_code, name) \ | ||
139 | static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \ | ||
140 | size_t len) \ | ||
141 | { \ | ||
142 | d_fnstart(6, NULL, "(attribute %p)\n", attr); \ | ||
143 | wlp_set_attr_hdr(&attr->hdr, type_code, len); \ | ||
144 | memcpy(attr->name, value, len); \ | ||
145 | d_dump(6, NULL, attr, sizeof(*attr) + len); \ | ||
146 | d_fnend(6, NULL, "(attribute %p)\n", attr); \ | ||
147 | return sizeof(*attr) + len; \ | ||
148 | } | ||
149 | |||
150 | wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name) | ||
151 | wlp_vset(char *, WLP_ATTR_MANUF, manufacturer) | ||
152 | wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type) | ||
153 | wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name) | ||
154 | wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr) | ||
155 | wlp_vset(char *, WLP_ATTR_SERIAL, serial) | ||
156 | wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name) | ||
157 | wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e) | ||
158 | wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r) | ||
159 | wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid) | ||
160 | wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type) | ||
161 | /*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/ | ||
162 | wlp_set(u8, WLP_ATTR_WLP_VER, version) | ||
163 | wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err) | ||
164 | wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd) | ||
165 | wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl) | ||
166 | wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status) | ||
167 | wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast) | ||
168 | wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce) | ||
169 | wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce) | ||
170 | wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag) | ||
171 | wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt) | ||
172 | |||
173 | /** | ||
174 | * Fill in the WSS information attributes | ||
175 | * | ||
176 | * We currently only support one WSS, and this is assumed in this function | ||
177 | * that can populate only one WSS information attribute. | ||
178 | */ | ||
179 | static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr, | ||
180 | struct wlp_wss *wss) | ||
181 | { | ||
182 | size_t datalen; | ||
183 | void *ptr = attr->wss_info; | ||
184 | size_t used = sizeof(*attr); | ||
185 | d_fnstart(6, NULL, "(attribute %p)\n", attr); | ||
186 | datalen = sizeof(struct wlp_wss_info) + strlen(wss->name); | ||
187 | wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen); | ||
188 | used = wlp_set_wssid(ptr, &wss->wssid); | ||
189 | used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name)); | ||
190 | used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll); | ||
191 | used += wlp_set_wss_sec_status(ptr + used, wss->secure_status); | ||
192 | used += wlp_set_wss_bcast(ptr + used, &wss->bcast); | ||
193 | d_dump(6, NULL, attr, sizeof(*attr) + datalen); | ||
194 | d_fnend(6, NULL, "(attribute %p, used %d)\n", | ||
195 | attr, (int)(sizeof(*attr) + used)); | ||
196 | return sizeof(*attr) + used; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * Verify attribute header | ||
201 | * | ||
202 | * @hdr: Pointer to attribute header that will be verified. | ||
203 | * @type: Expected attribute type. | ||
204 | * @len: Expected length of attribute value (excluding header). | ||
205 | * | ||
206 | * Most attribute values have a known length even when they do have a | ||
207 | * length field. This knowledge can be used via this function to verify | ||
208 | * that the length field matches the expected value. | ||
209 | */ | ||
210 | static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr, | ||
211 | enum wlp_attr_type type, unsigned len) | ||
212 | { | ||
213 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
214 | |||
215 | if (le16_to_cpu(hdr->type) != type) { | ||
216 | dev_err(dev, "WLP: unexpected header type. Expected " | ||
217 | "%u, got %u.\n", type, le16_to_cpu(hdr->type)); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | if (le16_to_cpu(hdr->length) != len) { | ||
221 | dev_err(dev, "WLP: unexpected length in header. Expected " | ||
222 | "%u, got %u.\n", len, le16_to_cpu(hdr->length)); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * Check if header of WSS information attribute valid | ||
230 | * | ||
231 | * @returns: length of WSS attributes (value of length attribute field) if | ||
232 | * valid WSS information attribute found | ||
233 | * -ENODATA if no WSS information attribute found | ||
234 | * -EIO other error occured | ||
235 | * | ||
236 | * The WSS information attribute is optional. The function will be provided | ||
237 | * with a pointer to data that could _potentially_ be a WSS information | ||
238 | * attribute. If a valid WSS information attribute is found it will return | ||
239 | * 0, if no WSS information attribute is found it will return -ENODATA, and | ||
240 | * another error will be returned if it is a WSS information attribute, but | ||
241 | * some parsing failure occured. | ||
242 | */ | ||
243 | static int wlp_check_wss_info_attr_hdr(struct wlp *wlp, | ||
244 | struct wlp_attr_hdr *hdr, size_t buflen) | ||
245 | { | ||
246 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
247 | size_t len; | ||
248 | int result = 0; | ||
249 | |||
250 | if (buflen < sizeof(*hdr)) { | ||
251 | dev_err(dev, "WLP: Not enough space in buffer to parse" | ||
252 | " WSS information attribute header.\n"); | ||
253 | result = -EIO; | ||
254 | goto out; | ||
255 | } | ||
256 | if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) { | ||
257 | /* WSS information is optional */ | ||
258 | result = -ENODATA; | ||
259 | goto out; | ||
260 | } | ||
261 | len = le16_to_cpu(hdr->length); | ||
262 | if (buflen < sizeof(*hdr) + len) { | ||
263 | dev_err(dev, "WLP: Not enough space in buffer to parse " | ||
264 | "variable data. Got %d, expected %d.\n", | ||
265 | (int)buflen, (int)(sizeof(*hdr) + len)); | ||
266 | result = -EIO; | ||
267 | goto out; | ||
268 | } | ||
269 | result = len; | ||
270 | out: | ||
271 | return result; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Get value of attribute from fixed size attribute field. | ||
277 | * | ||
278 | * @attr: Pointer to attribute field. | ||
279 | * @value: Pointer to variable in which attribute value will be placed. | ||
280 | * @buflen: Size of buffer in which attribute field (including header) | ||
281 | * can be found. | ||
282 | * @returns: Amount of given buffer consumed by parsing for this attribute. | ||
283 | * | ||
284 | * The size and type of the value is known by the type of the attribute. | ||
285 | */ | ||
286 | #define wlp_get(type, type_code, name) \ | ||
287 | ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \ | ||
288 | type *value, ssize_t buflen) \ | ||
289 | { \ | ||
290 | struct device *dev = &wlp->rc->uwb_dev.dev; \ | ||
291 | if (buflen < 0) \ | ||
292 | return -EINVAL; \ | ||
293 | if (buflen < sizeof(*attr)) { \ | ||
294 | dev_err(dev, "WLP: Not enough space in buffer to parse" \ | ||
295 | " attribute field. Need %d, received %zu\n", \ | ||
296 | (int)sizeof(*attr), buflen); \ | ||
297 | return -EIO; \ | ||
298 | } \ | ||
299 | if (wlp_check_attr_hdr(wlp, &attr->hdr, type_code, \ | ||
300 | sizeof(attr->name)) < 0) { \ | ||
301 | dev_err(dev, "WLP: Header verification failed. \n"); \ | ||
302 | return -EINVAL; \ | ||
303 | } \ | ||
304 | *value = attr->name; \ | ||
305 | return sizeof(*attr); \ | ||
306 | } | ||
307 | |||
308 | #define wlp_get_sparse(type, type_code, name) \ | ||
309 | static wlp_get(type, type_code, name) | ||
310 | |||
311 | /** | ||
312 | * Get value of attribute from variable sized attribute field. | ||
313 | * | ||
314 | * @max: The maximum size of this attribute. This value is dictated by | ||
315 | * the maximum value from the WLP specification. | ||
316 | * | ||
317 | * @attr: Pointer to attribute field. | ||
318 | * @value: Pointer to variable that will contain the value. The memory | ||
319 | * must already have been allocated for this value. | ||
320 | * @buflen: Size of buffer in which attribute field (including header) | ||
321 | * can be found. | ||
322 | * @returns: Amount of given bufferconsumed by parsing for this attribute. | ||
323 | */ | ||
324 | #define wlp_vget(type_val, type_code, name, max) \ | ||
325 | static ssize_t wlp_get_##name(struct wlp *wlp, \ | ||
326 | struct wlp_attr_##name *attr, \ | ||
327 | type_val *value, ssize_t buflen) \ | ||
328 | { \ | ||
329 | struct device *dev = &wlp->rc->uwb_dev.dev; \ | ||
330 | size_t len; \ | ||
331 | if (buflen < 0) \ | ||
332 | return -EINVAL; \ | ||
333 | if (buflen < sizeof(*attr)) { \ | ||
334 | dev_err(dev, "WLP: Not enough space in buffer to parse" \ | ||
335 | " header.\n"); \ | ||
336 | return -EIO; \ | ||
337 | } \ | ||
338 | if (le16_to_cpu(attr->hdr.type) != type_code) { \ | ||
339 | dev_err(dev, "WLP: Unexpected attribute type. Got %u, " \ | ||
340 | "expected %u.\n", le16_to_cpu(attr->hdr.type), \ | ||
341 | type_code); \ | ||
342 | return -EINVAL; \ | ||
343 | } \ | ||
344 | len = le16_to_cpu(attr->hdr.length); \ | ||
345 | if (len > max) { \ | ||
346 | dev_err(dev, "WLP: Attribute larger than maximum " \ | ||
347 | "allowed. Received %zu, max is %d.\n", len, \ | ||
348 | (int)max); \ | ||
349 | return -EFBIG; \ | ||
350 | } \ | ||
351 | if (buflen < sizeof(*attr) + len) { \ | ||
352 | dev_err(dev, "WLP: Not enough space in buffer to parse "\ | ||
353 | "variable data.\n"); \ | ||
354 | return -EIO; \ | ||
355 | } \ | ||
356 | memcpy(value, (void *) attr + sizeof(*attr), len); \ | ||
357 | return sizeof(*attr) + len; \ | ||
358 | } | ||
359 | |||
360 | wlp_get(u8, WLP_ATTR_WLP_VER, version) | ||
361 | wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd) | ||
362 | wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type) | ||
363 | wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err) | ||
364 | wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e) | ||
365 | wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r) | ||
366 | wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid) | ||
367 | wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl) | ||
368 | wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status) | ||
369 | wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast) | ||
370 | wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag) | ||
371 | wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt) | ||
372 | wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce) | ||
373 | wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce) | ||
374 | |||
375 | /* The buffers for the device info attributes can be found in the | ||
376 | * wlp_device_info struct. These buffers contain one byte more than the | ||
377 | * max allowed by the spec - this is done to be able to add the | ||
378 | * terminating \0 for user display. This terminating byte is not required | ||
379 | * in the actual attribute field (because it has a length field) so the | ||
380 | * maximum allowed for this value is one less than its size in the | ||
381 | * structure. | ||
382 | */ | ||
383 | wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name, | ||
384 | FIELD_SIZEOF(struct wlp_wss, name) - 1) | ||
385 | wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name, | ||
386 | FIELD_SIZEOF(struct wlp_device_info, name) - 1) | ||
387 | wlp_vget(char, WLP_ATTR_MANUF, manufacturer, | ||
388 | FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1) | ||
389 | wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name, | ||
390 | FIELD_SIZEOF(struct wlp_device_info, model_name) - 1) | ||
391 | wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr, | ||
392 | FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1) | ||
393 | wlp_vget(char, WLP_ATTR_SERIAL, serial, | ||
394 | FIELD_SIZEOF(struct wlp_device_info, serial) - 1) | ||
395 | |||
396 | /** | ||
397 | * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info | ||
398 | * | ||
399 | * @attr: pointer to WSS name attribute in WSS information attribute field | ||
400 | * @info: structure that will be populated with data from WSS information | ||
401 | * field (WSS name, Accept enroll, secure status, broadcast address) | ||
402 | * @buflen: size of buffer | ||
403 | * | ||
404 | * Although the WSSID attribute forms part of the WSS info attribute it is | ||
405 | * retrieved separately and stored in a different location. | ||
406 | */ | ||
407 | static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp, | ||
408 | struct wlp_attr_hdr *attr, | ||
409 | struct wlp_wss_tmp_info *info, | ||
410 | ssize_t buflen) | ||
411 | { | ||
412 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
413 | void *ptr = attr; | ||
414 | size_t used = 0; | ||
415 | ssize_t result = -EINVAL; | ||
416 | |||
417 | d_printf(6, dev, "WLP: WSS info: Retrieving WSS name\n"); | ||
418 | result = wlp_get_wss_name(wlp, ptr, info->name, buflen); | ||
419 | if (result < 0) { | ||
420 | dev_err(dev, "WLP: unable to obtain WSS name from " | ||
421 | "WSS info in D2 message.\n"); | ||
422 | goto error_parse; | ||
423 | } | ||
424 | used += result; | ||
425 | d_printf(6, dev, "WLP: WSS info: Retrieving accept enroll\n"); | ||
426 | result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll, | ||
427 | buflen - used); | ||
428 | if (result < 0) { | ||
429 | dev_err(dev, "WLP: unable to obtain accepting " | ||
430 | "enrollment from WSS info in D2 message.\n"); | ||
431 | goto error_parse; | ||
432 | } | ||
433 | if (info->accept_enroll != 0 && info->accept_enroll != 1) { | ||
434 | dev_err(dev, "WLP: invalid value for accepting " | ||
435 | "enrollment in D2 message.\n"); | ||
436 | result = -EINVAL; | ||
437 | goto error_parse; | ||
438 | } | ||
439 | used += result; | ||
440 | d_printf(6, dev, "WLP: WSS info: Retrieving secure status\n"); | ||
441 | result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status, | ||
442 | buflen - used); | ||
443 | if (result < 0) { | ||
444 | dev_err(dev, "WLP: unable to obtain secure " | ||
445 | "status from WSS info in D2 message.\n"); | ||
446 | goto error_parse; | ||
447 | } | ||
448 | if (info->sec_status != 0 && info->sec_status != 1) { | ||
449 | dev_err(dev, "WLP: invalid value for secure " | ||
450 | "status in D2 message.\n"); | ||
451 | result = -EINVAL; | ||
452 | goto error_parse; | ||
453 | } | ||
454 | used += result; | ||
455 | d_printf(6, dev, "WLP: WSS info: Retrieving broadcast\n"); | ||
456 | result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast, | ||
457 | buflen - used); | ||
458 | if (result < 0) { | ||
459 | dev_err(dev, "WLP: unable to obtain broadcast " | ||
460 | "address from WSS info in D2 message.\n"); | ||
461 | goto error_parse; | ||
462 | } | ||
463 | used += result; | ||
464 | result = used; | ||
465 | error_parse: | ||
466 | return result; | ||
467 | } | ||
468 | |||
469 | /** | ||
470 | * Create a new WSSID entry for the neighbor, allocate temporary storage | ||
471 | * | ||
472 | * Each neighbor can have many WSS active. We maintain a list of WSSIDs | ||
473 | * advertised by neighbor. During discovery we also cache information about | ||
474 | * these WSS in temporary storage. | ||
475 | * | ||
476 | * The temporary storage will be removed after it has been used (eg. | ||
477 | * displayed to user), the wssid element will be removed from the list when | ||
478 | * the neighbor is rediscovered or when it disappears. | ||
479 | */ | ||
480 | static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp, | ||
481 | struct wlp_neighbor_e *neighbor) | ||
482 | { | ||
483 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
484 | struct wlp_wssid_e *wssid_e; | ||
485 | |||
486 | wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL); | ||
487 | if (wssid_e == NULL) { | ||
488 | dev_err(dev, "WLP: unable to allocate memory " | ||
489 | "for WSS information.\n"); | ||
490 | goto error_alloc; | ||
491 | } | ||
492 | wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL); | ||
493 | if (wssid_e->info == NULL) { | ||
494 | dev_err(dev, "WLP: unable to allocate memory " | ||
495 | "for temporary WSS information.\n"); | ||
496 | kfree(wssid_e); | ||
497 | wssid_e = NULL; | ||
498 | goto error_alloc; | ||
499 | } | ||
500 | list_add(&wssid_e->node, &neighbor->wssid); | ||
501 | error_alloc: | ||
502 | return wssid_e; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * Parse WSS information attribute | ||
507 | * | ||
508 | * @attr: pointer to WSS information attribute header | ||
509 | * @buflen: size of buffer in which WSS information attribute appears | ||
510 | * @wssid: will place wssid from WSS info attribute in this location | ||
511 | * @wss_info: will place other information from WSS information attribute | ||
512 | * in this location | ||
513 | * | ||
514 | * memory for @wssid and @wss_info must be allocated when calling this | ||
515 | */ | ||
516 | static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr, | ||
517 | size_t buflen, struct wlp_uuid *wssid, | ||
518 | struct wlp_wss_tmp_info *wss_info) | ||
519 | { | ||
520 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
521 | ssize_t result; | ||
522 | size_t len; | ||
523 | size_t used = 0; | ||
524 | void *ptr; | ||
525 | |||
526 | result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr, | ||
527 | buflen); | ||
528 | if (result < 0) | ||
529 | goto out; | ||
530 | len = result; | ||
531 | used = sizeof(*attr); | ||
532 | ptr = attr; | ||
533 | d_printf(6, dev, "WLP: WSS info: Retrieving WSSID\n"); | ||
534 | result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used); | ||
535 | if (result < 0) { | ||
536 | dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n"); | ||
537 | goto out; | ||
538 | } | ||
539 | used += result; | ||
540 | result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info, | ||
541 | buflen - used); | ||
542 | if (result < 0) { | ||
543 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
544 | "from WSS information attributes. \n"); | ||
545 | goto out; | ||
546 | } | ||
547 | used += result; | ||
548 | if (len + sizeof(*attr) != used) { | ||
549 | dev_err(dev, "WLP: Amount of data parsed does not " | ||
550 | "match length field. Parsed %zu, length " | ||
551 | "field %zu. \n", used, len); | ||
552 | result = -EINVAL; | ||
553 | goto out; | ||
554 | } | ||
555 | result = used; | ||
556 | d_printf(6, dev, "WLP: Successfully parsed WLP information " | ||
557 | "attribute. used %zu bytes\n", used); | ||
558 | out: | ||
559 | return result; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * Retrieve WSS info from association frame | ||
564 | * | ||
565 | * @attr: pointer to WSS information attribute | ||
566 | * @neighbor: ptr to neighbor being discovered, NULL if enrollment in | ||
567 | * progress | ||
568 | * @wss: ptr to WSS being enrolled in, NULL if discovery in progress | ||
569 | * @buflen: size of buffer in which WSS information appears | ||
570 | * | ||
571 | * The WSS information attribute appears in the D2 association message. | ||
572 | * This message is used in two ways: to discover all neighbors or to enroll | ||
573 | * into a WSS activated by a neighbor. During discovery we only want to | ||
574 | * store the WSS info in a cache, to be deleted right after it has been | ||
575 | * used (eg. displayed to the user). During enrollment we store the WSS | ||
576 | * information for the lifetime of enrollment. | ||
577 | * | ||
578 | * During discovery we are interested in all WSS information, during | ||
579 | * enrollment we are only interested in the WSS being enrolled in. Even so, | ||
580 | * when in enrollment we keep parsing the message after finding the WSS of | ||
581 | * interest, this simplifies the calling routine in that it can be sure | ||
582 | * that all WSS information attributes have been parsed out of the message. | ||
583 | * | ||
584 | * Association frame is process with nbmutex held. The list access is safe. | ||
585 | */ | ||
586 | static ssize_t wlp_get_all_wss_info(struct wlp *wlp, | ||
587 | struct wlp_attr_wss_info *attr, | ||
588 | struct wlp_neighbor_e *neighbor, | ||
589 | struct wlp_wss *wss, ssize_t buflen) | ||
590 | { | ||
591 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
592 | size_t used = 0; | ||
593 | ssize_t result = -EINVAL; | ||
594 | struct wlp_attr_wss_info *cur; | ||
595 | struct wlp_uuid wssid; | ||
596 | struct wlp_wss_tmp_info wss_info; | ||
597 | unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */ | ||
598 | struct wlp_wssid_e *wssid_e; | ||
599 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
600 | |||
601 | d_fnstart(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d \n", | ||
602 | wlp, attr, neighbor, wss, (int)buflen); | ||
603 | if (buflen < 0) | ||
604 | goto out; | ||
605 | |||
606 | if (neighbor != NULL && wss == NULL) | ||
607 | enroll = 0; /* discovery */ | ||
608 | else if (wss != NULL && neighbor == NULL) | ||
609 | enroll = 1; /* enrollment */ | ||
610 | else | ||
611 | goto out; | ||
612 | |||
613 | cur = attr; | ||
614 | while (buflen - used > 0) { | ||
615 | memset(&wss_info, 0, sizeof(wss_info)); | ||
616 | cur = (void *)cur + used; | ||
617 | result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid, | ||
618 | &wss_info); | ||
619 | if (result == -ENODATA) { | ||
620 | result = used; | ||
621 | goto out; | ||
622 | } else if (result < 0) { | ||
623 | dev_err(dev, "WLP: Unable to parse WSS information " | ||
624 | "from WSS information attribute. \n"); | ||
625 | result = -EINVAL; | ||
626 | goto error_parse; | ||
627 | } | ||
628 | if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) { | ||
629 | if (wss_info.accept_enroll != 1) { | ||
630 | dev_err(dev, "WLP: Requested WSS does " | ||
631 | "not accept enrollment.\n"); | ||
632 | result = -EINVAL; | ||
633 | goto out; | ||
634 | } | ||
635 | memcpy(wss->name, wss_info.name, sizeof(wss->name)); | ||
636 | wss->bcast = wss_info.bcast; | ||
637 | wss->secure_status = wss_info.sec_status; | ||
638 | wss->accept_enroll = wss_info.accept_enroll; | ||
639 | wss->state = WLP_WSS_STATE_PART_ENROLLED; | ||
640 | wlp_wss_uuid_print(buf, sizeof(buf), &wssid); | ||
641 | d_printf(2, dev, "WLP: Found WSS %s. Enrolling.\n", | ||
642 | buf); | ||
643 | } else { | ||
644 | wssid_e = wlp_create_wssid_e(wlp, neighbor); | ||
645 | if (wssid_e == NULL) { | ||
646 | dev_err(dev, "WLP: Cannot create new WSSID " | ||
647 | "entry for neighbor %02x:%02x.\n", | ||
648 | neighbor->uwb_dev->dev_addr.data[1], | ||
649 | neighbor->uwb_dev->dev_addr.data[0]); | ||
650 | result = -ENOMEM; | ||
651 | goto out; | ||
652 | } | ||
653 | wssid_e->wssid = wssid; | ||
654 | *wssid_e->info = wss_info; | ||
655 | } | ||
656 | used += result; | ||
657 | } | ||
658 | result = used; | ||
659 | error_parse: | ||
660 | if (result < 0 && !enroll) /* this was a discovery */ | ||
661 | wlp_remove_neighbor_tmp_info(neighbor); | ||
662 | out: | ||
663 | d_fnend(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d, " | ||
664 | "result %d \n", wlp, attr, neighbor, wss, (int)buflen, | ||
665 | (int)result); | ||
666 | return result; | ||
667 | |||
668 | } | ||
669 | |||
670 | /** | ||
671 | * Parse WSS information attributes into cache for discovery | ||
672 | * | ||
673 | * @attr: the first WSS information attribute in message | ||
674 | * @neighbor: the neighbor whose cache will be populated | ||
675 | * @buflen: size of the input buffer | ||
676 | */ | ||
677 | static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp, | ||
678 | struct wlp_attr_wss_info *attr, | ||
679 | struct wlp_neighbor_e *neighbor, | ||
680 | ssize_t buflen) | ||
681 | { | ||
682 | return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen); | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * Parse WSS information attributes into WSS struct for enrollment | ||
687 | * | ||
688 | * @attr: the first WSS information attribute in message | ||
689 | * @wss: the WSS that will be enrolled | ||
690 | * @buflen: size of the input buffer | ||
691 | */ | ||
692 | static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp, | ||
693 | struct wlp_attr_wss_info *attr, | ||
694 | struct wlp_wss *wss, ssize_t buflen) | ||
695 | { | ||
696 | return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen); | ||
697 | } | ||
698 | |||
699 | /** | ||
700 | * Construct a D1 association frame | ||
701 | * | ||
702 | * We use the radio control functions to determine the values of the device | ||
703 | * properties. These are of variable length and the total space needed is | ||
704 | * tallied first before we start constructing the message. The radio | ||
705 | * control functions return strings that are terminated with \0. This | ||
706 | * character should not be included in the message (there is a length field | ||
707 | * accompanying it in the attribute). | ||
708 | */ | ||
709 | static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss, | ||
710 | struct sk_buff **skb) | ||
711 | { | ||
712 | |||
713 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
714 | int result = 0; | ||
715 | struct wlp_device_info *info; | ||
716 | size_t used = 0; | ||
717 | struct wlp_frame_assoc *_d1; | ||
718 | struct sk_buff *_skb; | ||
719 | void *d1_itr; | ||
720 | |||
721 | d_fnstart(6, dev, "wlp %p\n", wlp); | ||
722 | if (wlp->dev_info == NULL) { | ||
723 | result = __wlp_setup_device_info(wlp); | ||
724 | if (result < 0) { | ||
725 | dev_err(dev, "WLP: Unable to setup device " | ||
726 | "information for D1 message.\n"); | ||
727 | goto error; | ||
728 | } | ||
729 | } | ||
730 | info = wlp->dev_info; | ||
731 | d_printf(6, dev, "Local properties:\n" | ||
732 | "Device name (%d bytes): %s\n" | ||
733 | "Model name (%d bytes): %s\n" | ||
734 | "Manufacturer (%d bytes): %s\n" | ||
735 | "Model number (%d bytes): %s\n" | ||
736 | "Serial number (%d bytes): %s\n" | ||
737 | "Primary device type: \n" | ||
738 | " Category: %d \n" | ||
739 | " OUI: %02x:%02x:%02x \n" | ||
740 | " OUI Subdivision: %u \n", | ||
741 | (int)strlen(info->name), info->name, | ||
742 | (int)strlen(info->model_name), info->model_name, | ||
743 | (int)strlen(info->manufacturer), info->manufacturer, | ||
744 | (int)strlen(info->model_nr), info->model_nr, | ||
745 | (int)strlen(info->serial), info->serial, | ||
746 | info->prim_dev_type.category, | ||
747 | info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1], | ||
748 | info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv); | ||
749 | _skb = dev_alloc_skb(sizeof(*_d1) | ||
750 | + sizeof(struct wlp_attr_uuid_e) | ||
751 | + sizeof(struct wlp_attr_wss_sel_mthd) | ||
752 | + sizeof(struct wlp_attr_dev_name) | ||
753 | + strlen(info->name) | ||
754 | + sizeof(struct wlp_attr_manufacturer) | ||
755 | + strlen(info->manufacturer) | ||
756 | + sizeof(struct wlp_attr_model_name) | ||
757 | + strlen(info->model_name) | ||
758 | + sizeof(struct wlp_attr_model_nr) | ||
759 | + strlen(info->model_nr) | ||
760 | + sizeof(struct wlp_attr_serial) | ||
761 | + strlen(info->serial) | ||
762 | + sizeof(struct wlp_attr_prim_dev_type) | ||
763 | + sizeof(struct wlp_attr_wlp_assc_err)); | ||
764 | if (_skb == NULL) { | ||
765 | dev_err(dev, "WLP: Cannot allocate memory for association " | ||
766 | "message.\n"); | ||
767 | result = -ENOMEM; | ||
768 | goto error; | ||
769 | } | ||
770 | _d1 = (void *) _skb->data; | ||
771 | d_printf(6, dev, "D1 starts at %p \n", _d1); | ||
772 | _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
773 | _d1->hdr.type = WLP_FRAME_ASSOCIATION; | ||
774 | _d1->type = WLP_ASSOC_D1; | ||
775 | |||
776 | wlp_set_version(&_d1->version, WLP_VERSION); | ||
777 | wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1); | ||
778 | d1_itr = _d1->attr; | ||
779 | used = wlp_set_uuid_e(d1_itr, &wlp->uuid); | ||
780 | used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT); | ||
781 | used += wlp_set_dev_name(d1_itr + used, info->name, | ||
782 | strlen(info->name)); | ||
783 | used += wlp_set_manufacturer(d1_itr + used, info->manufacturer, | ||
784 | strlen(info->manufacturer)); | ||
785 | used += wlp_set_model_name(d1_itr + used, info->model_name, | ||
786 | strlen(info->model_name)); | ||
787 | used += wlp_set_model_nr(d1_itr + used, info->model_nr, | ||
788 | strlen(info->model_nr)); | ||
789 | used += wlp_set_serial(d1_itr + used, info->serial, | ||
790 | strlen(info->serial)); | ||
791 | used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type); | ||
792 | used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE); | ||
793 | skb_put(_skb, sizeof(*_d1) + used); | ||
794 | d_printf(6, dev, "D1 message:\n"); | ||
795 | d_dump(6, dev, _d1, sizeof(*_d1) | ||
796 | + sizeof(struct wlp_attr_uuid_e) | ||
797 | + sizeof(struct wlp_attr_wss_sel_mthd) | ||
798 | + sizeof(struct wlp_attr_dev_name) | ||
799 | + strlen(info->name) | ||
800 | + sizeof(struct wlp_attr_manufacturer) | ||
801 | + strlen(info->manufacturer) | ||
802 | + sizeof(struct wlp_attr_model_name) | ||
803 | + strlen(info->model_name) | ||
804 | + sizeof(struct wlp_attr_model_nr) | ||
805 | + strlen(info->model_nr) | ||
806 | + sizeof(struct wlp_attr_serial) | ||
807 | + strlen(info->serial) | ||
808 | + sizeof(struct wlp_attr_prim_dev_type) | ||
809 | + sizeof(struct wlp_attr_wlp_assc_err)); | ||
810 | *skb = _skb; | ||
811 | error: | ||
812 | d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); | ||
813 | return result; | ||
814 | } | ||
815 | |||
816 | /** | ||
817 | * Construct a D2 association frame | ||
818 | * | ||
819 | * We use the radio control functions to determine the values of the device | ||
820 | * properties. These are of variable length and the total space needed is | ||
821 | * tallied first before we start constructing the message. The radio | ||
822 | * control functions return strings that are terminated with \0. This | ||
823 | * character should not be included in the message (there is a length field | ||
824 | * accompanying it in the attribute). | ||
825 | */ | ||
826 | static | ||
827 | int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss, | ||
828 | struct sk_buff **skb, struct wlp_uuid *uuid_e) | ||
829 | { | ||
830 | |||
831 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
832 | int result = 0; | ||
833 | struct wlp_device_info *info; | ||
834 | size_t used = 0; | ||
835 | struct wlp_frame_assoc *_d2; | ||
836 | struct sk_buff *_skb; | ||
837 | void *d2_itr; | ||
838 | size_t mem_needed; | ||
839 | |||
840 | d_fnstart(6, dev, "wlp %p\n", wlp); | ||
841 | if (wlp->dev_info == NULL) { | ||
842 | result = __wlp_setup_device_info(wlp); | ||
843 | if (result < 0) { | ||
844 | dev_err(dev, "WLP: Unable to setup device " | ||
845 | "information for D2 message.\n"); | ||
846 | goto error; | ||
847 | } | ||
848 | } | ||
849 | info = wlp->dev_info; | ||
850 | d_printf(6, dev, "Local properties:\n" | ||
851 | "Device name (%d bytes): %s\n" | ||
852 | "Model name (%d bytes): %s\n" | ||
853 | "Manufacturer (%d bytes): %s\n" | ||
854 | "Model number (%d bytes): %s\n" | ||
855 | "Serial number (%d bytes): %s\n" | ||
856 | "Primary device type: \n" | ||
857 | " Category: %d \n" | ||
858 | " OUI: %02x:%02x:%02x \n" | ||
859 | " OUI Subdivision: %u \n", | ||
860 | (int)strlen(info->name), info->name, | ||
861 | (int)strlen(info->model_name), info->model_name, | ||
862 | (int)strlen(info->manufacturer), info->manufacturer, | ||
863 | (int)strlen(info->model_nr), info->model_nr, | ||
864 | (int)strlen(info->serial), info->serial, | ||
865 | info->prim_dev_type.category, | ||
866 | info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1], | ||
867 | info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv); | ||
868 | mem_needed = sizeof(*_d2) | ||
869 | + sizeof(struct wlp_attr_uuid_e) | ||
870 | + sizeof(struct wlp_attr_uuid_r) | ||
871 | + sizeof(struct wlp_attr_dev_name) | ||
872 | + strlen(info->name) | ||
873 | + sizeof(struct wlp_attr_manufacturer) | ||
874 | + strlen(info->manufacturer) | ||
875 | + sizeof(struct wlp_attr_model_name) | ||
876 | + strlen(info->model_name) | ||
877 | + sizeof(struct wlp_attr_model_nr) | ||
878 | + strlen(info->model_nr) | ||
879 | + sizeof(struct wlp_attr_serial) | ||
880 | + strlen(info->serial) | ||
881 | + sizeof(struct wlp_attr_prim_dev_type) | ||
882 | + sizeof(struct wlp_attr_wlp_assc_err); | ||
883 | if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE) | ||
884 | mem_needed += sizeof(struct wlp_attr_wss_info) | ||
885 | + sizeof(struct wlp_wss_info) | ||
886 | + strlen(wlp->wss.name); | ||
887 | _skb = dev_alloc_skb(mem_needed); | ||
888 | if (_skb == NULL) { | ||
889 | dev_err(dev, "WLP: Cannot allocate memory for association " | ||
890 | "message.\n"); | ||
891 | result = -ENOMEM; | ||
892 | goto error; | ||
893 | } | ||
894 | _d2 = (void *) _skb->data; | ||
895 | d_printf(6, dev, "D2 starts at %p \n", _d2); | ||
896 | _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
897 | _d2->hdr.type = WLP_FRAME_ASSOCIATION; | ||
898 | _d2->type = WLP_ASSOC_D2; | ||
899 | |||
900 | wlp_set_version(&_d2->version, WLP_VERSION); | ||
901 | wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2); | ||
902 | d2_itr = _d2->attr; | ||
903 | used = wlp_set_uuid_e(d2_itr, uuid_e); | ||
904 | used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid); | ||
905 | if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE) | ||
906 | used += wlp_set_wss_info(d2_itr + used, &wlp->wss); | ||
907 | used += wlp_set_dev_name(d2_itr + used, info->name, | ||
908 | strlen(info->name)); | ||
909 | used += wlp_set_manufacturer(d2_itr + used, info->manufacturer, | ||
910 | strlen(info->manufacturer)); | ||
911 | used += wlp_set_model_name(d2_itr + used, info->model_name, | ||
912 | strlen(info->model_name)); | ||
913 | used += wlp_set_model_nr(d2_itr + used, info->model_nr, | ||
914 | strlen(info->model_nr)); | ||
915 | used += wlp_set_serial(d2_itr + used, info->serial, | ||
916 | strlen(info->serial)); | ||
917 | used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type); | ||
918 | used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE); | ||
919 | skb_put(_skb, sizeof(*_d2) + used); | ||
920 | d_printf(6, dev, "D2 message:\n"); | ||
921 | d_dump(6, dev, _d2, mem_needed); | ||
922 | *skb = _skb; | ||
923 | error: | ||
924 | d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); | ||
925 | return result; | ||
926 | } | ||
927 | |||
928 | /** | ||
929 | * Allocate memory for and populate fields of F0 association frame | ||
930 | * | ||
931 | * Currently (while focusing on unsecure enrollment) we ignore the | ||
932 | * nonce's that could be placed in the message. Only the error field is | ||
933 | * populated by the value provided by the caller. | ||
934 | */ | ||
935 | static | ||
936 | int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb, | ||
937 | enum wlp_assc_error error) | ||
938 | { | ||
939 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
940 | int result = -ENOMEM; | ||
941 | struct { | ||
942 | struct wlp_frame_assoc f0_hdr; | ||
943 | struct wlp_attr_enonce enonce; | ||
944 | struct wlp_attr_rnonce rnonce; | ||
945 | struct wlp_attr_wlp_assc_err assc_err; | ||
946 | } *f0; | ||
947 | struct sk_buff *_skb; | ||
948 | struct wlp_nonce tmp; | ||
949 | |||
950 | d_fnstart(6, dev, "wlp %p\n", wlp); | ||
951 | _skb = dev_alloc_skb(sizeof(*f0)); | ||
952 | if (_skb == NULL) { | ||
953 | dev_err(dev, "WLP: Unable to allocate memory for F0 " | ||
954 | "association frame. \n"); | ||
955 | goto error_alloc; | ||
956 | } | ||
957 | f0 = (void *) _skb->data; | ||
958 | d_printf(6, dev, "F0 starts at %p \n", f0); | ||
959 | f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
960 | f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
961 | f0->f0_hdr.type = WLP_ASSOC_F0; | ||
962 | wlp_set_version(&f0->f0_hdr.version, WLP_VERSION); | ||
963 | wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0); | ||
964 | memset(&tmp, 0, sizeof(tmp)); | ||
965 | wlp_set_enonce(&f0->enonce, &tmp); | ||
966 | wlp_set_rnonce(&f0->rnonce, &tmp); | ||
967 | wlp_set_wlp_assc_err(&f0->assc_err, error); | ||
968 | skb_put(_skb, sizeof(*f0)); | ||
969 | *skb = _skb; | ||
970 | result = 0; | ||
971 | error_alloc: | ||
972 | d_fnend(6, dev, "wlp %p, result %d \n", wlp, result); | ||
973 | return result; | ||
974 | } | ||
975 | |||
976 | /** | ||
977 | * Parse F0 frame | ||
978 | * | ||
979 | * We just retrieve the values and print it as an error to the user. | ||
980 | * Calling function already knows an error occured (F0 indicates error), so | ||
981 | * we just parse the content as debug for higher layers. | ||
982 | */ | ||
983 | int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb) | ||
984 | { | ||
985 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
986 | struct wlp_frame_assoc *f0 = (void *) skb->data; | ||
987 | void *ptr = skb->data; | ||
988 | size_t len = skb->len; | ||
989 | size_t used; | ||
990 | ssize_t result; | ||
991 | struct wlp_nonce enonce, rnonce; | ||
992 | enum wlp_assc_error assc_err; | ||
993 | char enonce_buf[WLP_WSS_NONCE_STRSIZE]; | ||
994 | char rnonce_buf[WLP_WSS_NONCE_STRSIZE]; | ||
995 | |||
996 | used = sizeof(*f0); | ||
997 | result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used); | ||
998 | if (result < 0) { | ||
999 | dev_err(dev, "WLP: unable to obtain Enrollee nonce " | ||
1000 | "attribute from F0 message.\n"); | ||
1001 | goto error_parse; | ||
1002 | } | ||
1003 | used += result; | ||
1004 | result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used); | ||
1005 | if (result < 0) { | ||
1006 | dev_err(dev, "WLP: unable to obtain Registrar nonce " | ||
1007 | "attribute from F0 message.\n"); | ||
1008 | goto error_parse; | ||
1009 | } | ||
1010 | used += result; | ||
1011 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
1012 | if (result < 0) { | ||
1013 | dev_err(dev, "WLP: unable to obtain WLP Association error " | ||
1014 | "attribute from F0 message.\n"); | ||
1015 | goto error_parse; | ||
1016 | } | ||
1017 | wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce); | ||
1018 | wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce); | ||
1019 | dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee " | ||
1020 | "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n", | ||
1021 | enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err)); | ||
1022 | result = 0; | ||
1023 | error_parse: | ||
1024 | return result; | ||
1025 | } | ||
1026 | |||
1027 | /** | ||
1028 | * Retrieve variable device information from association message | ||
1029 | * | ||
1030 | * The device information parsed is not required in any message. This | ||
1031 | * routine will thus not fail if an attribute is not present. | ||
1032 | * The attributes are expected in a certain order, even if all are not | ||
1033 | * present. The "attribute type" value is used to ensure the attributes | ||
1034 | * are parsed in the correct order. | ||
1035 | * | ||
1036 | * If an error is encountered during parsing the function will return an | ||
1037 | * error code, when this happens the given device_info structure may be | ||
1038 | * partially filled. | ||
1039 | */ | ||
1040 | static | ||
1041 | int wlp_get_variable_info(struct wlp *wlp, void *data, | ||
1042 | struct wlp_device_info *dev_info, ssize_t len) | ||
1043 | { | ||
1044 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1045 | size_t used = 0; | ||
1046 | struct wlp_attr_hdr *hdr; | ||
1047 | ssize_t result = 0; | ||
1048 | unsigned last = 0; | ||
1049 | |||
1050 | while (len - used > 0) { | ||
1051 | if (len - used < sizeof(*hdr)) { | ||
1052 | dev_err(dev, "WLP: Partial data in frame, cannot " | ||
1053 | "parse. \n"); | ||
1054 | goto error_parse; | ||
1055 | } | ||
1056 | hdr = data + used; | ||
1057 | switch (le16_to_cpu(hdr->type)) { | ||
1058 | case WLP_ATTR_MANUF: | ||
1059 | if (last >= WLP_ATTR_MANUF) { | ||
1060 | dev_err(dev, "WLP: Incorrect order of " | ||
1061 | "attribute values in D1 msg.\n"); | ||
1062 | goto error_parse; | ||
1063 | } | ||
1064 | result = wlp_get_manufacturer(wlp, data + used, | ||
1065 | dev_info->manufacturer, | ||
1066 | len - used); | ||
1067 | if (result < 0) { | ||
1068 | dev_err(dev, "WLP: Unable to obtain " | ||
1069 | "Manufacturer attribute from D1 " | ||
1070 | "message.\n"); | ||
1071 | goto error_parse; | ||
1072 | } | ||
1073 | last = WLP_ATTR_MANUF; | ||
1074 | used += result; | ||
1075 | break; | ||
1076 | case WLP_ATTR_MODEL_NAME: | ||
1077 | if (last >= WLP_ATTR_MODEL_NAME) { | ||
1078 | dev_err(dev, "WLP: Incorrect order of " | ||
1079 | "attribute values in D1 msg.\n"); | ||
1080 | goto error_parse; | ||
1081 | } | ||
1082 | result = wlp_get_model_name(wlp, data + used, | ||
1083 | dev_info->model_name, | ||
1084 | len - used); | ||
1085 | if (result < 0) { | ||
1086 | dev_err(dev, "WLP: Unable to obtain Model " | ||
1087 | "name attribute from D1 message.\n"); | ||
1088 | goto error_parse; | ||
1089 | } | ||
1090 | last = WLP_ATTR_MODEL_NAME; | ||
1091 | used += result; | ||
1092 | break; | ||
1093 | case WLP_ATTR_MODEL_NR: | ||
1094 | if (last >= WLP_ATTR_MODEL_NR) { | ||
1095 | dev_err(dev, "WLP: Incorrect order of " | ||
1096 | "attribute values in D1 msg.\n"); | ||
1097 | goto error_parse; | ||
1098 | } | ||
1099 | result = wlp_get_model_nr(wlp, data + used, | ||
1100 | dev_info->model_nr, | ||
1101 | len - used); | ||
1102 | if (result < 0) { | ||
1103 | dev_err(dev, "WLP: Unable to obtain Model " | ||
1104 | "number attribute from D1 message.\n"); | ||
1105 | goto error_parse; | ||
1106 | } | ||
1107 | last = WLP_ATTR_MODEL_NR; | ||
1108 | used += result; | ||
1109 | break; | ||
1110 | case WLP_ATTR_SERIAL: | ||
1111 | if (last >= WLP_ATTR_SERIAL) { | ||
1112 | dev_err(dev, "WLP: Incorrect order of " | ||
1113 | "attribute values in D1 msg.\n"); | ||
1114 | goto error_parse; | ||
1115 | } | ||
1116 | result = wlp_get_serial(wlp, data + used, | ||
1117 | dev_info->serial, len - used); | ||
1118 | if (result < 0) { | ||
1119 | dev_err(dev, "WLP: Unable to obtain Serial " | ||
1120 | "number attribute from D1 message.\n"); | ||
1121 | goto error_parse; | ||
1122 | } | ||
1123 | last = WLP_ATTR_SERIAL; | ||
1124 | used += result; | ||
1125 | break; | ||
1126 | case WLP_ATTR_PRI_DEV_TYPE: | ||
1127 | if (last >= WLP_ATTR_PRI_DEV_TYPE) { | ||
1128 | dev_err(dev, "WLP: Incorrect order of " | ||
1129 | "attribute values in D1 msg.\n"); | ||
1130 | goto error_parse; | ||
1131 | } | ||
1132 | result = wlp_get_prim_dev_type(wlp, data + used, | ||
1133 | &dev_info->prim_dev_type, | ||
1134 | len - used); | ||
1135 | if (result < 0) { | ||
1136 | dev_err(dev, "WLP: Unable to obtain Primary " | ||
1137 | "device type attribute from D1 " | ||
1138 | "message.\n"); | ||
1139 | goto error_parse; | ||
1140 | } | ||
1141 | dev_info->prim_dev_type.category = | ||
1142 | le16_to_cpu(dev_info->prim_dev_type.category); | ||
1143 | dev_info->prim_dev_type.subID = | ||
1144 | le16_to_cpu(dev_info->prim_dev_type.subID); | ||
1145 | last = WLP_ATTR_PRI_DEV_TYPE; | ||
1146 | used += result; | ||
1147 | break; | ||
1148 | default: | ||
1149 | /* This is not variable device information. */ | ||
1150 | goto out; | ||
1151 | break; | ||
1152 | } | ||
1153 | } | ||
1154 | out: | ||
1155 | return used; | ||
1156 | error_parse: | ||
1157 | return -EINVAL; | ||
1158 | } | ||
1159 | |||
1160 | /** | ||
1161 | * Parse incoming D1 frame, populate attribute values | ||
1162 | * | ||
1163 | * Caller provides pointers to memory already allocated for attributes | ||
1164 | * expected in the D1 frame. These variables will be populated. | ||
1165 | */ | ||
1166 | static | ||
1167 | int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb, | ||
1168 | struct wlp_uuid *uuid_e, | ||
1169 | enum wlp_wss_sel_mthd *sel_mthd, | ||
1170 | struct wlp_device_info *dev_info, | ||
1171 | enum wlp_assc_error *assc_err) | ||
1172 | { | ||
1173 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1174 | struct wlp_frame_assoc *d1 = (void *) skb->data; | ||
1175 | void *ptr = skb->data; | ||
1176 | size_t len = skb->len; | ||
1177 | size_t used; | ||
1178 | ssize_t result; | ||
1179 | |||
1180 | used = sizeof(*d1); | ||
1181 | result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used); | ||
1182 | if (result < 0) { | ||
1183 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 " | ||
1184 | "message.\n"); | ||
1185 | goto error_parse; | ||
1186 | } | ||
1187 | used += result; | ||
1188 | result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used); | ||
1189 | if (result < 0) { | ||
1190 | dev_err(dev, "WLP: unable to obtain WSS selection method " | ||
1191 | "from D1 message.\n"); | ||
1192 | goto error_parse; | ||
1193 | } | ||
1194 | used += result; | ||
1195 | result = wlp_get_dev_name(wlp, ptr + used, dev_info->name, | ||
1196 | len - used); | ||
1197 | if (result < 0) { | ||
1198 | dev_err(dev, "WLP: unable to obtain Device Name from D1 " | ||
1199 | "message.\n"); | ||
1200 | goto error_parse; | ||
1201 | } | ||
1202 | used += result; | ||
1203 | result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used); | ||
1204 | if (result < 0) { | ||
1205 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1206 | "D1 message.\n"); | ||
1207 | goto error_parse; | ||
1208 | } | ||
1209 | used += result; | ||
1210 | result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used); | ||
1211 | if (result < 0) { | ||
1212 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1213 | "Information from D1 message.\n"); | ||
1214 | goto error_parse; | ||
1215 | } | ||
1216 | result = 0; | ||
1217 | error_parse: | ||
1218 | return result; | ||
1219 | } | ||
1220 | /** | ||
1221 | * Handle incoming D1 frame | ||
1222 | * | ||
1223 | * The frame has already been verified to contain an Association header with | ||
1224 | * the correct version number. Parse the incoming frame, construct and send | ||
1225 | * a D2 frame in response. | ||
1226 | * | ||
1227 | * It is not clear what to do with most fields in the incoming D1 frame. We | ||
1228 | * retrieve and discard the information here for now. | ||
1229 | */ | ||
1230 | void wlp_handle_d1_frame(struct work_struct *ws) | ||
1231 | { | ||
1232 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1233 | struct wlp_assoc_frame_ctx, | ||
1234 | ws); | ||
1235 | struct wlp *wlp = frame_ctx->wlp; | ||
1236 | struct wlp_wss *wss = &wlp->wss; | ||
1237 | struct sk_buff *skb = frame_ctx->skb; | ||
1238 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1239 | int result; | ||
1240 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1241 | struct wlp_uuid uuid_e; | ||
1242 | enum wlp_wss_sel_mthd sel_mthd = 0; | ||
1243 | struct wlp_device_info dev_info; | ||
1244 | enum wlp_assc_error assc_err; | ||
1245 | char uuid[WLP_WSS_UUID_STRSIZE]; | ||
1246 | struct sk_buff *resp = NULL; | ||
1247 | |||
1248 | /* Parse D1 frame */ | ||
1249 | d_fnstart(6, dev, "WLP: handle D1 frame. wlp = %p, skb = %p\n", | ||
1250 | wlp, skb); | ||
1251 | mutex_lock(&wss->mutex); | ||
1252 | mutex_lock(&wlp->mutex); /* to access wlp->uuid */ | ||
1253 | memset(&dev_info, 0, sizeof(dev_info)); | ||
1254 | result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info, | ||
1255 | &assc_err); | ||
1256 | if (result < 0) { | ||
1257 | dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n"); | ||
1258 | kfree_skb(skb); | ||
1259 | goto out; | ||
1260 | } | ||
1261 | wlp_wss_uuid_print(uuid, sizeof(uuid), &uuid_e); | ||
1262 | d_printf(6, dev, "From D1 frame:\n" | ||
1263 | "UUID-E: %s\n" | ||
1264 | "Selection method: %d\n" | ||
1265 | "Device name (%d bytes): %s\n" | ||
1266 | "Model name (%d bytes): %s\n" | ||
1267 | "Manufacturer (%d bytes): %s\n" | ||
1268 | "Model number (%d bytes): %s\n" | ||
1269 | "Serial number (%d bytes): %s\n" | ||
1270 | "Primary device type: \n" | ||
1271 | " Category: %d \n" | ||
1272 | " OUI: %02x:%02x:%02x \n" | ||
1273 | " OUI Subdivision: %u \n", | ||
1274 | uuid, sel_mthd, | ||
1275 | (int)strlen(dev_info.name), dev_info.name, | ||
1276 | (int)strlen(dev_info.model_name), dev_info.model_name, | ||
1277 | (int)strlen(dev_info.manufacturer), dev_info.manufacturer, | ||
1278 | (int)strlen(dev_info.model_nr), dev_info.model_nr, | ||
1279 | (int)strlen(dev_info.serial), dev_info.serial, | ||
1280 | dev_info.prim_dev_type.category, | ||
1281 | dev_info.prim_dev_type.OUI[0], | ||
1282 | dev_info.prim_dev_type.OUI[1], | ||
1283 | dev_info.prim_dev_type.OUI[2], | ||
1284 | dev_info.prim_dev_type.OUIsubdiv); | ||
1285 | |||
1286 | kfree_skb(skb); | ||
1287 | if (!wlp_uuid_is_set(&wlp->uuid)) { | ||
1288 | dev_err(dev, "WLP: UUID is not set. Set via sysfs to " | ||
1289 | "proceed. Respong to D1 message with error F0.\n"); | ||
1290 | result = wlp_build_assoc_f0(wlp, &resp, | ||
1291 | WLP_ASSOC_ERROR_NOT_READY); | ||
1292 | if (result < 0) { | ||
1293 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1294 | goto out; | ||
1295 | } | ||
1296 | } else { | ||
1297 | /* Construct D2 frame */ | ||
1298 | result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e); | ||
1299 | if (result < 0) { | ||
1300 | dev_err(dev, "WLP: Unable to construct D2 message.\n"); | ||
1301 | goto out; | ||
1302 | } | ||
1303 | } | ||
1304 | /* Send D2 frame */ | ||
1305 | BUG_ON(wlp->xmit_frame == NULL); | ||
1306 | result = wlp->xmit_frame(wlp, resp, src); | ||
1307 | if (result < 0) { | ||
1308 | dev_err(dev, "WLP: Unable to transmit D2 association " | ||
1309 | "message: %d\n", result); | ||
1310 | if (result == -ENXIO) | ||
1311 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1312 | /* We could try again ... */ | ||
1313 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1314 | } | ||
1315 | out: | ||
1316 | kfree(frame_ctx); | ||
1317 | mutex_unlock(&wlp->mutex); | ||
1318 | mutex_unlock(&wss->mutex); | ||
1319 | d_fnend(6, dev, "WLP: handle D1 frame. wlp = %p\n", wlp); | ||
1320 | } | ||
1321 | |||
1322 | /** | ||
1323 | * Parse incoming D2 frame, create and populate temporary cache | ||
1324 | * | ||
1325 | * @skb: socket buffer in which D2 frame can be found | ||
1326 | * @neighbor: the neighbor that sent the D2 frame | ||
1327 | * | ||
1328 | * Will allocate memory for temporary storage of information learned during | ||
1329 | * discovery. | ||
1330 | */ | ||
1331 | int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb, | ||
1332 | struct wlp_neighbor_e *neighbor) | ||
1333 | { | ||
1334 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1335 | struct wlp_frame_assoc *d2 = (void *) skb->data; | ||
1336 | void *ptr = skb->data; | ||
1337 | size_t len = skb->len; | ||
1338 | size_t used; | ||
1339 | ssize_t result; | ||
1340 | struct wlp_uuid uuid_e; | ||
1341 | struct wlp_device_info *nb_info; | ||
1342 | enum wlp_assc_error assc_err; | ||
1343 | |||
1344 | used = sizeof(*d2); | ||
1345 | result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used); | ||
1346 | if (result < 0) { | ||
1347 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 " | ||
1348 | "message.\n"); | ||
1349 | goto error_parse; | ||
1350 | } | ||
1351 | if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) { | ||
1352 | dev_err(dev, "WLP: UUID-E in incoming D2 does not match " | ||
1353 | "local UUID sent in D1. \n"); | ||
1354 | goto error_parse; | ||
1355 | } | ||
1356 | used += result; | ||
1357 | result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used); | ||
1358 | if (result < 0) { | ||
1359 | dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 " | ||
1360 | "message.\n"); | ||
1361 | goto error_parse; | ||
1362 | } | ||
1363 | used += result; | ||
1364 | result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor, | ||
1365 | len - used); | ||
1366 | if (result < 0) { | ||
1367 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
1368 | "from D2 message.\n"); | ||
1369 | goto error_parse; | ||
1370 | } | ||
1371 | used += result; | ||
1372 | neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL); | ||
1373 | if (neighbor->info == NULL) { | ||
1374 | dev_err(dev, "WLP: cannot allocate memory to store device " | ||
1375 | "info.\n"); | ||
1376 | result = -ENOMEM; | ||
1377 | goto error_parse; | ||
1378 | } | ||
1379 | nb_info = neighbor->info; | ||
1380 | result = wlp_get_dev_name(wlp, ptr + used, nb_info->name, | ||
1381 | len - used); | ||
1382 | if (result < 0) { | ||
1383 | dev_err(dev, "WLP: unable to obtain Device Name from D2 " | ||
1384 | "message.\n"); | ||
1385 | goto error_parse; | ||
1386 | } | ||
1387 | used += result; | ||
1388 | result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used); | ||
1389 | if (result < 0) { | ||
1390 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1391 | "D2 message.\n"); | ||
1392 | goto error_parse; | ||
1393 | } | ||
1394 | used += result; | ||
1395 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
1396 | if (result < 0) { | ||
1397 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1398 | "Information from D2 message.\n"); | ||
1399 | goto error_parse; | ||
1400 | } | ||
1401 | if (assc_err != WLP_ASSOC_ERROR_NONE) { | ||
1402 | dev_err(dev, "WLP: neighbor device returned association " | ||
1403 | "error %d\n", assc_err); | ||
1404 | result = -EINVAL; | ||
1405 | goto error_parse; | ||
1406 | } | ||
1407 | result = 0; | ||
1408 | error_parse: | ||
1409 | if (result < 0) | ||
1410 | wlp_remove_neighbor_tmp_info(neighbor); | ||
1411 | return result; | ||
1412 | } | ||
1413 | |||
1414 | /** | ||
1415 | * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in | ||
1416 | * | ||
1417 | * @wss: our WSS that will be enrolled | ||
1418 | * @skb: socket buffer in which D2 frame can be found | ||
1419 | * @neighbor: the neighbor that sent the D2 frame | ||
1420 | * @wssid: the wssid of the WSS in which we want to enroll | ||
1421 | * | ||
1422 | * Forms part of enrollment sequence. We are trying to enroll in WSS with | ||
1423 | * @wssid by using @neighbor as registrar. A D1 message was sent to | ||
1424 | * @neighbor and now we need to parse the D2 response. The neighbor's | ||
1425 | * response is searched for the requested WSS and if found (and it accepts | ||
1426 | * enrollment), we store the information. | ||
1427 | */ | ||
1428 | int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb, | ||
1429 | struct wlp_neighbor_e *neighbor, | ||
1430 | struct wlp_uuid *wssid) | ||
1431 | { | ||
1432 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
1433 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1434 | void *ptr = skb->data; | ||
1435 | size_t len = skb->len; | ||
1436 | size_t used; | ||
1437 | ssize_t result; | ||
1438 | struct wlp_uuid uuid_e; | ||
1439 | struct wlp_uuid uuid_r; | ||
1440 | struct wlp_device_info nb_info; | ||
1441 | enum wlp_assc_error assc_err; | ||
1442 | char uuid_bufA[WLP_WSS_UUID_STRSIZE]; | ||
1443 | char uuid_bufB[WLP_WSS_UUID_STRSIZE]; | ||
1444 | |||
1445 | used = sizeof(struct wlp_frame_assoc); | ||
1446 | result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used); | ||
1447 | if (result < 0) { | ||
1448 | dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 " | ||
1449 | "message.\n"); | ||
1450 | goto error_parse; | ||
1451 | } | ||
1452 | if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) { | ||
1453 | dev_err(dev, "WLP: UUID-E in incoming D2 does not match " | ||
1454 | "local UUID sent in D1. \n"); | ||
1455 | goto error_parse; | ||
1456 | } | ||
1457 | used += result; | ||
1458 | result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used); | ||
1459 | if (result < 0) { | ||
1460 | dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 " | ||
1461 | "message.\n"); | ||
1462 | goto error_parse; | ||
1463 | } | ||
1464 | if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) { | ||
1465 | wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA), | ||
1466 | &neighbor->uuid); | ||
1467 | wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r); | ||
1468 | dev_err(dev, "WLP: UUID of neighbor does not match UUID " | ||
1469 | "learned during discovery. Originally discovered: %s, " | ||
1470 | "now from D2 message: %s\n", uuid_bufA, uuid_bufB); | ||
1471 | result = -EINVAL; | ||
1472 | goto error_parse; | ||
1473 | } | ||
1474 | used += result; | ||
1475 | wss->wssid = *wssid; | ||
1476 | result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used); | ||
1477 | if (result < 0) { | ||
1478 | dev_err(dev, "WLP: unable to obtain WSS information " | ||
1479 | "from D2 message.\n"); | ||
1480 | goto error_parse; | ||
1481 | } | ||
1482 | if (wss->state != WLP_WSS_STATE_PART_ENROLLED) { | ||
1483 | dev_err(dev, "WLP: D2 message did not contain information " | ||
1484 | "for successful enrollment. \n"); | ||
1485 | result = -EINVAL; | ||
1486 | goto error_parse; | ||
1487 | } | ||
1488 | used += result; | ||
1489 | /* Place device information on stack to continue parsing of message */ | ||
1490 | result = wlp_get_dev_name(wlp, ptr + used, nb_info.name, | ||
1491 | len - used); | ||
1492 | if (result < 0) { | ||
1493 | dev_err(dev, "WLP: unable to obtain Device Name from D2 " | ||
1494 | "message.\n"); | ||
1495 | goto error_parse; | ||
1496 | } | ||
1497 | used += result; | ||
1498 | result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used); | ||
1499 | if (result < 0) { | ||
1500 | dev_err(dev, "WLP: unable to obtain Device Information from " | ||
1501 | "D2 message.\n"); | ||
1502 | goto error_parse; | ||
1503 | } | ||
1504 | used += result; | ||
1505 | result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used); | ||
1506 | if (result < 0) { | ||
1507 | dev_err(dev, "WLP: unable to obtain WLP Association Error " | ||
1508 | "Information from D2 message.\n"); | ||
1509 | goto error_parse; | ||
1510 | } | ||
1511 | if (assc_err != WLP_ASSOC_ERROR_NONE) { | ||
1512 | dev_err(dev, "WLP: neighbor device returned association " | ||
1513 | "error %d\n", assc_err); | ||
1514 | if (wss->state == WLP_WSS_STATE_PART_ENROLLED) { | ||
1515 | dev_err(dev, "WLP: Enrolled in WSS (should not " | ||
1516 | "happen according to spec). Undoing. \n"); | ||
1517 | wlp_wss_reset(wss); | ||
1518 | } | ||
1519 | result = -EINVAL; | ||
1520 | goto error_parse; | ||
1521 | } | ||
1522 | result = 0; | ||
1523 | error_parse: | ||
1524 | return result; | ||
1525 | } | ||
1526 | |||
1527 | /** | ||
1528 | * Parse C3/C4 frame into provided variables | ||
1529 | * | ||
1530 | * @wssid: will point to copy of wssid retrieved from C3/C4 frame | ||
1531 | * @tag: will point to copy of tag retrieved from C3/C4 frame | ||
1532 | * @virt_addr: will point to copy of virtual address retrieved from C3/C4 | ||
1533 | * frame. | ||
1534 | * | ||
1535 | * Calling function has to allocate memory for these values. | ||
1536 | * | ||
1537 | * skb contains a valid C3/C4 frame, return the individual fields of this | ||
1538 | * frame in the provided variables. | ||
1539 | */ | ||
1540 | int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb, | ||
1541 | struct wlp_uuid *wssid, u8 *tag, | ||
1542 | struct uwb_mac_addr *virt_addr) | ||
1543 | { | ||
1544 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1545 | int result; | ||
1546 | void *ptr = skb->data; | ||
1547 | size_t len = skb->len; | ||
1548 | size_t used; | ||
1549 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
1550 | struct wlp_frame_assoc *assoc = ptr; | ||
1551 | |||
1552 | d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb); | ||
1553 | used = sizeof(*assoc); | ||
1554 | result = wlp_get_wssid(wlp, ptr + used, wssid, len - used); | ||
1555 | if (result < 0) { | ||
1556 | dev_err(dev, "WLP: unable to obtain WSSID attribute from " | ||
1557 | "%s message.\n", wlp_assoc_frame_str(assoc->type)); | ||
1558 | goto error_parse; | ||
1559 | } | ||
1560 | used += result; | ||
1561 | result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used); | ||
1562 | if (result < 0) { | ||
1563 | dev_err(dev, "WLP: unable to obtain WSS tag attribute from " | ||
1564 | "%s message.\n", wlp_assoc_frame_str(assoc->type)); | ||
1565 | goto error_parse; | ||
1566 | } | ||
1567 | used += result; | ||
1568 | result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used); | ||
1569 | if (result < 0) { | ||
1570 | dev_err(dev, "WLP: unable to obtain WSS virtual address " | ||
1571 | "attribute from %s message.\n", | ||
1572 | wlp_assoc_frame_str(assoc->type)); | ||
1573 | goto error_parse; | ||
1574 | } | ||
1575 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
1576 | d_printf(6, dev, "WLP: parsed: WSSID %s, tag 0x%02x, virt " | ||
1577 | "%02x:%02x:%02x:%02x:%02x:%02x \n", buf, *tag, | ||
1578 | virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], | ||
1579 | virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]); | ||
1580 | |||
1581 | error_parse: | ||
1582 | d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result); | ||
1583 | return result; | ||
1584 | } | ||
1585 | |||
1586 | /** | ||
1587 | * Allocate memory for and populate fields of C1 or C2 association frame | ||
1588 | * | ||
1589 | * The C1 and C2 association frames appear identical - except for the type. | ||
1590 | */ | ||
1591 | static | ||
1592 | int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss, | ||
1593 | struct sk_buff **skb, enum wlp_assoc_type type) | ||
1594 | { | ||
1595 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1596 | int result = -ENOMEM; | ||
1597 | struct { | ||
1598 | struct wlp_frame_assoc c_hdr; | ||
1599 | struct wlp_attr_wssid wssid; | ||
1600 | } *c; | ||
1601 | struct sk_buff *_skb; | ||
1602 | |||
1603 | d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss); | ||
1604 | _skb = dev_alloc_skb(sizeof(*c)); | ||
1605 | if (_skb == NULL) { | ||
1606 | dev_err(dev, "WLP: Unable to allocate memory for C1/C2 " | ||
1607 | "association frame. \n"); | ||
1608 | goto error_alloc; | ||
1609 | } | ||
1610 | c = (void *) _skb->data; | ||
1611 | d_printf(6, dev, "C1/C2 starts at %p \n", c); | ||
1612 | c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
1613 | c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
1614 | c->c_hdr.type = type; | ||
1615 | wlp_set_version(&c->c_hdr.version, WLP_VERSION); | ||
1616 | wlp_set_msg_type(&c->c_hdr.msg_type, type); | ||
1617 | wlp_set_wssid(&c->wssid, &wss->wssid); | ||
1618 | skb_put(_skb, sizeof(*c)); | ||
1619 | d_printf(6, dev, "C1/C2 message:\n"); | ||
1620 | d_dump(6, dev, c, sizeof(*c)); | ||
1621 | *skb = _skb; | ||
1622 | result = 0; | ||
1623 | error_alloc: | ||
1624 | d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result); | ||
1625 | return result; | ||
1626 | } | ||
1627 | |||
1628 | |||
1629 | static | ||
1630 | int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss, | ||
1631 | struct sk_buff **skb) | ||
1632 | { | ||
1633 | return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1); | ||
1634 | } | ||
1635 | |||
1636 | static | ||
1637 | int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss, | ||
1638 | struct sk_buff **skb) | ||
1639 | { | ||
1640 | return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2); | ||
1641 | } | ||
1642 | |||
1643 | |||
1644 | /** | ||
1645 | * Allocate memory for and populate fields of C3 or C4 association frame | ||
1646 | * | ||
1647 | * The C3 and C4 association frames appear identical - except for the type. | ||
1648 | */ | ||
1649 | static | ||
1650 | int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss, | ||
1651 | struct sk_buff **skb, enum wlp_assoc_type type) | ||
1652 | { | ||
1653 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1654 | int result = -ENOMEM; | ||
1655 | struct { | ||
1656 | struct wlp_frame_assoc c_hdr; | ||
1657 | struct wlp_attr_wssid wssid; | ||
1658 | struct wlp_attr_wss_tag wss_tag; | ||
1659 | struct wlp_attr_wss_virt wss_virt; | ||
1660 | } *c; | ||
1661 | struct sk_buff *_skb; | ||
1662 | |||
1663 | d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss); | ||
1664 | _skb = dev_alloc_skb(sizeof(*c)); | ||
1665 | if (_skb == NULL) { | ||
1666 | dev_err(dev, "WLP: Unable to allocate memory for C3/C4 " | ||
1667 | "association frame. \n"); | ||
1668 | goto error_alloc; | ||
1669 | } | ||
1670 | c = (void *) _skb->data; | ||
1671 | d_printf(6, dev, "C3/C4 starts at %p \n", c); | ||
1672 | c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
1673 | c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION; | ||
1674 | c->c_hdr.type = type; | ||
1675 | wlp_set_version(&c->c_hdr.version, WLP_VERSION); | ||
1676 | wlp_set_msg_type(&c->c_hdr.msg_type, type); | ||
1677 | wlp_set_wssid(&c->wssid, &wss->wssid); | ||
1678 | wlp_set_wss_tag(&c->wss_tag, wss->tag); | ||
1679 | wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr); | ||
1680 | skb_put(_skb, sizeof(*c)); | ||
1681 | d_printf(6, dev, "C3/C4 message:\n"); | ||
1682 | d_dump(6, dev, c, sizeof(*c)); | ||
1683 | *skb = _skb; | ||
1684 | result = 0; | ||
1685 | error_alloc: | ||
1686 | d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result); | ||
1687 | return result; | ||
1688 | } | ||
1689 | |||
1690 | static | ||
1691 | int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss, | ||
1692 | struct sk_buff **skb) | ||
1693 | { | ||
1694 | return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3); | ||
1695 | } | ||
1696 | |||
1697 | static | ||
1698 | int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss, | ||
1699 | struct sk_buff **skb) | ||
1700 | { | ||
1701 | return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4); | ||
1702 | } | ||
1703 | |||
1704 | |||
1705 | #define wlp_send_assoc(type, id) \ | ||
1706 | static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \ | ||
1707 | struct uwb_dev_addr *dev_addr) \ | ||
1708 | { \ | ||
1709 | struct device *dev = &wlp->rc->uwb_dev.dev; \ | ||
1710 | int result; \ | ||
1711 | struct sk_buff *skb = NULL; \ | ||
1712 | d_fnstart(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \ | ||
1713 | wlp, wss, dev_addr->data[1], dev_addr->data[0]); \ | ||
1714 | d_printf(6, dev, "WLP: Constructing %s frame. \n", \ | ||
1715 | wlp_assoc_frame_str(id)); \ | ||
1716 | /* Build the frame */ \ | ||
1717 | result = wlp_build_assoc_##type(wlp, wss, &skb); \ | ||
1718 | if (result < 0) { \ | ||
1719 | dev_err(dev, "WLP: Unable to construct %s association " \ | ||
1720 | "frame: %d\n", wlp_assoc_frame_str(id), result);\ | ||
1721 | goto error_build_assoc; \ | ||
1722 | } \ | ||
1723 | /* Send the frame */ \ | ||
1724 | d_printf(6, dev, "Transmitting %s frame to %02x:%02x \n", \ | ||
1725 | wlp_assoc_frame_str(id), \ | ||
1726 | dev_addr->data[1], dev_addr->data[0]); \ | ||
1727 | BUG_ON(wlp->xmit_frame == NULL); \ | ||
1728 | result = wlp->xmit_frame(wlp, skb, dev_addr); \ | ||
1729 | if (result < 0) { \ | ||
1730 | dev_err(dev, "WLP: Unable to transmit %s association " \ | ||
1731 | "message: %d\n", wlp_assoc_frame_str(id), \ | ||
1732 | result); \ | ||
1733 | if (result == -ENXIO) \ | ||
1734 | dev_err(dev, "WLP: Is network interface " \ | ||
1735 | "up? \n"); \ | ||
1736 | goto error_xmit; \ | ||
1737 | } \ | ||
1738 | return 0; \ | ||
1739 | error_xmit: \ | ||
1740 | /* We could try again ... */ \ | ||
1741 | dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \ | ||
1742 | error_build_assoc: \ | ||
1743 | d_fnend(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \ | ||
1744 | wlp, wss, dev_addr->data[1], dev_addr->data[0]); \ | ||
1745 | return result; \ | ||
1746 | } | ||
1747 | |||
1748 | wlp_send_assoc(d1, WLP_ASSOC_D1) | ||
1749 | wlp_send_assoc(c1, WLP_ASSOC_C1) | ||
1750 | wlp_send_assoc(c3, WLP_ASSOC_C3) | ||
1751 | |||
1752 | int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss, | ||
1753 | struct uwb_dev_addr *dev_addr, | ||
1754 | enum wlp_assoc_type type) | ||
1755 | { | ||
1756 | int result = 0; | ||
1757 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1758 | switch (type) { | ||
1759 | case WLP_ASSOC_D1: | ||
1760 | result = wlp_send_assoc_d1(wlp, wss, dev_addr); | ||
1761 | break; | ||
1762 | case WLP_ASSOC_C1: | ||
1763 | result = wlp_send_assoc_c1(wlp, wss, dev_addr); | ||
1764 | break; | ||
1765 | case WLP_ASSOC_C3: | ||
1766 | result = wlp_send_assoc_c3(wlp, wss, dev_addr); | ||
1767 | break; | ||
1768 | default: | ||
1769 | dev_err(dev, "WLP: Received request to send unknown " | ||
1770 | "association message.\n"); | ||
1771 | result = -EINVAL; | ||
1772 | break; | ||
1773 | } | ||
1774 | return result; | ||
1775 | } | ||
1776 | |||
1777 | /** | ||
1778 | * Handle incoming C1 frame | ||
1779 | * | ||
1780 | * The frame has already been verified to contain an Association header with | ||
1781 | * the correct version number. Parse the incoming frame, construct and send | ||
1782 | * a C2 frame in response. | ||
1783 | */ | ||
1784 | void wlp_handle_c1_frame(struct work_struct *ws) | ||
1785 | { | ||
1786 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1787 | struct wlp_assoc_frame_ctx, | ||
1788 | ws); | ||
1789 | struct wlp *wlp = frame_ctx->wlp; | ||
1790 | struct wlp_wss *wss = &wlp->wss; | ||
1791 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1792 | struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data; | ||
1793 | unsigned int len = frame_ctx->skb->len; | ||
1794 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1795 | int result; | ||
1796 | struct wlp_uuid wssid; | ||
1797 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
1798 | struct sk_buff *resp = NULL; | ||
1799 | |||
1800 | /* Parse C1 frame */ | ||
1801 | d_fnstart(6, dev, "WLP: handle C1 frame. wlp = %p, c1 = %p\n", | ||
1802 | wlp, c1); | ||
1803 | mutex_lock(&wss->mutex); | ||
1804 | result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid, | ||
1805 | len - sizeof(*c1)); | ||
1806 | if (result < 0) { | ||
1807 | dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n"); | ||
1808 | goto out; | ||
1809 | } | ||
1810 | wlp_wss_uuid_print(buf, sizeof(buf), &wssid); | ||
1811 | d_printf(6, dev, "Received C1 frame with WSSID %s \n", buf); | ||
1812 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) | ||
1813 | && wss->state == WLP_WSS_STATE_ACTIVE) { | ||
1814 | d_printf(6, dev, "WSSID from C1 frame is known locally " | ||
1815 | "and is active\n"); | ||
1816 | /* Construct C2 frame */ | ||
1817 | result = wlp_build_assoc_c2(wlp, wss, &resp); | ||
1818 | if (result < 0) { | ||
1819 | dev_err(dev, "WLP: Unable to construct C2 message.\n"); | ||
1820 | goto out; | ||
1821 | } | ||
1822 | } else { | ||
1823 | d_printf(6, dev, "WSSID from C1 frame is not known locally " | ||
1824 | "or is not active\n"); | ||
1825 | /* Construct F0 frame */ | ||
1826 | result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); | ||
1827 | if (result < 0) { | ||
1828 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1829 | goto out; | ||
1830 | } | ||
1831 | } | ||
1832 | /* Send C2 frame */ | ||
1833 | d_printf(6, dev, "Transmitting response (C2/F0) frame to %02x:%02x \n", | ||
1834 | src->data[1], src->data[0]); | ||
1835 | BUG_ON(wlp->xmit_frame == NULL); | ||
1836 | result = wlp->xmit_frame(wlp, resp, src); | ||
1837 | if (result < 0) { | ||
1838 | dev_err(dev, "WLP: Unable to transmit response association " | ||
1839 | "message: %d\n", result); | ||
1840 | if (result == -ENXIO) | ||
1841 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1842 | /* We could try again ... */ | ||
1843 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1844 | } | ||
1845 | out: | ||
1846 | kfree_skb(frame_ctx->skb); | ||
1847 | kfree(frame_ctx); | ||
1848 | mutex_unlock(&wss->mutex); | ||
1849 | d_fnend(6, dev, "WLP: handle C1 frame. wlp = %p\n", wlp); | ||
1850 | } | ||
1851 | |||
1852 | /** | ||
1853 | * Handle incoming C3 frame | ||
1854 | * | ||
1855 | * The frame has already been verified to contain an Association header with | ||
1856 | * the correct version number. Parse the incoming frame, construct and send | ||
1857 | * a C4 frame in response. If the C3 frame identifies a WSS that is locally | ||
1858 | * active then we connect to this neighbor (add it to our EDA cache). | ||
1859 | */ | ||
1860 | void wlp_handle_c3_frame(struct work_struct *ws) | ||
1861 | { | ||
1862 | struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws, | ||
1863 | struct wlp_assoc_frame_ctx, | ||
1864 | ws); | ||
1865 | struct wlp *wlp = frame_ctx->wlp; | ||
1866 | struct wlp_wss *wss = &wlp->wss; | ||
1867 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1868 | struct sk_buff *skb = frame_ctx->skb; | ||
1869 | struct uwb_dev_addr *src = &frame_ctx->src; | ||
1870 | int result; | ||
1871 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
1872 | struct sk_buff *resp = NULL; | ||
1873 | struct wlp_uuid wssid; | ||
1874 | u8 tag; | ||
1875 | struct uwb_mac_addr virt_addr; | ||
1876 | |||
1877 | /* Parse C3 frame */ | ||
1878 | d_fnstart(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n", | ||
1879 | wlp, skb); | ||
1880 | mutex_lock(&wss->mutex); | ||
1881 | result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr); | ||
1882 | if (result < 0) { | ||
1883 | dev_err(dev, "WLP: unable to obtain values from C3 frame.\n"); | ||
1884 | goto out; | ||
1885 | } | ||
1886 | wlp_wss_uuid_print(buf, sizeof(buf), &wssid); | ||
1887 | d_printf(6, dev, "Received C3 frame with WSSID %s \n", buf); | ||
1888 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid)) | ||
1889 | && wss->state >= WLP_WSS_STATE_ACTIVE) { | ||
1890 | d_printf(6, dev, "WSSID from C3 frame is known locally " | ||
1891 | "and is active\n"); | ||
1892 | result = wlp_eda_update_node(&wlp->eda, src, wss, | ||
1893 | (void *) virt_addr.data, tag, | ||
1894 | WLP_WSS_CONNECTED); | ||
1895 | if (result < 0) { | ||
1896 | dev_err(dev, "WLP: Unable to update EDA cache " | ||
1897 | "with new connected neighbor information.\n"); | ||
1898 | result = wlp_build_assoc_f0(wlp, &resp, | ||
1899 | WLP_ASSOC_ERROR_INT); | ||
1900 | if (result < 0) { | ||
1901 | dev_err(dev, "WLP: Unable to construct F0 " | ||
1902 | "message.\n"); | ||
1903 | goto out; | ||
1904 | } | ||
1905 | } else { | ||
1906 | wss->state = WLP_WSS_STATE_CONNECTED; | ||
1907 | /* Construct C4 frame */ | ||
1908 | result = wlp_build_assoc_c4(wlp, wss, &resp); | ||
1909 | if (result < 0) { | ||
1910 | dev_err(dev, "WLP: Unable to construct C4 " | ||
1911 | "message.\n"); | ||
1912 | goto out; | ||
1913 | } | ||
1914 | } | ||
1915 | } else { | ||
1916 | d_printf(6, dev, "WSSID from C3 frame is not known locally " | ||
1917 | "or is not active\n"); | ||
1918 | /* Construct F0 frame */ | ||
1919 | result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV); | ||
1920 | if (result < 0) { | ||
1921 | dev_err(dev, "WLP: Unable to construct F0 message.\n"); | ||
1922 | goto out; | ||
1923 | } | ||
1924 | } | ||
1925 | /* Send C4 frame */ | ||
1926 | d_printf(6, dev, "Transmitting response (C4/F0) frame to %02x:%02x \n", | ||
1927 | src->data[1], src->data[0]); | ||
1928 | BUG_ON(wlp->xmit_frame == NULL); | ||
1929 | result = wlp->xmit_frame(wlp, resp, src); | ||
1930 | if (result < 0) { | ||
1931 | dev_err(dev, "WLP: Unable to transmit response association " | ||
1932 | "message: %d\n", result); | ||
1933 | if (result == -ENXIO) | ||
1934 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
1935 | /* We could try again ... */ | ||
1936 | dev_kfree_skb_any(resp); /* we need to free if tx fails */ | ||
1937 | } | ||
1938 | out: | ||
1939 | kfree_skb(frame_ctx->skb); | ||
1940 | kfree(frame_ctx); | ||
1941 | mutex_unlock(&wss->mutex); | ||
1942 | d_fnend(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n", | ||
1943 | wlp, skb); | ||
1944 | } | ||
1945 | |||
1946 | |||
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c new file mode 100644 index 000000000000..1bb9b1f97d47 --- /dev/null +++ b/drivers/uwb/wlp/sysfs.c | |||
@@ -0,0 +1,709 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * sysfs functions | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: Docs | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/wlp.h> | ||
28 | #include "wlp-internal.h" | ||
29 | |||
30 | static | ||
31 | size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize, | ||
32 | struct wlp_wssid_e *wssid_e) | ||
33 | { | ||
34 | size_t used = 0; | ||
35 | used += scnprintf(buf, bufsize, " WSS: "); | ||
36 | used += wlp_wss_uuid_print(buf + used, bufsize - used, | ||
37 | &wssid_e->wssid); | ||
38 | |||
39 | if (wssid_e->info != NULL) { | ||
40 | used += scnprintf(buf + used, bufsize - used, " "); | ||
41 | used += uwb_mac_addr_print(buf + used, bufsize - used, | ||
42 | &wssid_e->info->bcast); | ||
43 | used += scnprintf(buf + used, bufsize - used, " %u %u %s\n", | ||
44 | wssid_e->info->accept_enroll, | ||
45 | wssid_e->info->sec_status, | ||
46 | wssid_e->info->name); | ||
47 | } | ||
48 | return used; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Print out information learned from neighbor discovery | ||
53 | * | ||
54 | * Some fields being printed may not be included in the device discovery | ||
55 | * information (it is not mandatory). We are thus careful how the | ||
56 | * information is printed to ensure it is clear to the user what field is | ||
57 | * being referenced. | ||
58 | * The information being printed is for one time use - temporary storage is | ||
59 | * cleaned after it is printed. | ||
60 | * | ||
61 | * Ideally sysfs output should be on one line. The information printed here | ||
62 | * contain a few strings so it will be hard to parse if they are all | ||
63 | * printed on the same line - without agreeing on a standard field | ||
64 | * separator. | ||
65 | */ | ||
66 | static | ||
67 | ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf, | ||
68 | size_t bufsize) | ||
69 | { | ||
70 | size_t used = 0; | ||
71 | struct wlp_neighbor_e *neighb; | ||
72 | struct wlp_wssid_e *wssid_e; | ||
73 | |||
74 | mutex_lock(&wlp->nbmutex); | ||
75 | used = scnprintf(buf, bufsize, "#Neighbor information\n" | ||
76 | "#uuid dev_addr\n" | ||
77 | "# Device Name:\n# Model Name:\n# Manufacturer:\n" | ||
78 | "# Model Nr:\n# Serial:\n" | ||
79 | "# Pri Dev type: CategoryID OUI OUISubdiv " | ||
80 | "SubcategoryID\n" | ||
81 | "# WSS: WSSID WSS_name accept_enroll sec_status " | ||
82 | "bcast\n" | ||
83 | "# WSS: WSSID WSS_name accept_enroll sec_status " | ||
84 | "bcast\n\n"); | ||
85 | list_for_each_entry(neighb, &wlp->neighbors, node) { | ||
86 | if (bufsize - used <= 0) | ||
87 | goto out; | ||
88 | used += wlp_wss_uuid_print(buf + used, bufsize - used, | ||
89 | &neighb->uuid); | ||
90 | buf[used++] = ' '; | ||
91 | used += uwb_dev_addr_print(buf + used, bufsize - used, | ||
92 | &neighb->uwb_dev->dev_addr); | ||
93 | if (neighb->info != NULL) | ||
94 | used += scnprintf(buf + used, bufsize - used, | ||
95 | "\n Device Name: %s\n" | ||
96 | " Model Name: %s\n" | ||
97 | " Manufacturer:%s \n" | ||
98 | " Model Nr: %s\n" | ||
99 | " Serial: %s\n" | ||
100 | " Pri Dev type: " | ||
101 | "%u %02x:%02x:%02x %u %u\n", | ||
102 | neighb->info->name, | ||
103 | neighb->info->model_name, | ||
104 | neighb->info->manufacturer, | ||
105 | neighb->info->model_nr, | ||
106 | neighb->info->serial, | ||
107 | neighb->info->prim_dev_type.category, | ||
108 | neighb->info->prim_dev_type.OUI[0], | ||
109 | neighb->info->prim_dev_type.OUI[1], | ||
110 | neighb->info->prim_dev_type.OUI[2], | ||
111 | neighb->info->prim_dev_type.OUIsubdiv, | ||
112 | neighb->info->prim_dev_type.subID); | ||
113 | list_for_each_entry(wssid_e, &neighb->wssid, node) { | ||
114 | used += wlp_wss_wssid_e_print(buf + used, | ||
115 | bufsize - used, | ||
116 | wssid_e); | ||
117 | } | ||
118 | buf[used++] = '\n'; | ||
119 | wlp_remove_neighbor_tmp_info(neighb); | ||
120 | } | ||
121 | |||
122 | |||
123 | out: | ||
124 | mutex_unlock(&wlp->nbmutex); | ||
125 | return used; | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Show properties of all WSS in neighborhood. | ||
131 | * | ||
132 | * Will trigger a complete discovery of WSS activated by this device and | ||
133 | * its neighbors. | ||
134 | */ | ||
135 | ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf) | ||
136 | { | ||
137 | wlp_discover(wlp); | ||
138 | return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE); | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(wlp_neighborhood_show); | ||
141 | |||
142 | static | ||
143 | ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf, | ||
144 | size_t bufsize) | ||
145 | { | ||
146 | ssize_t result; | ||
147 | |||
148 | result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid); | ||
149 | result += scnprintf(buf + result, bufsize - result, " "); | ||
150 | result += uwb_mac_addr_print(buf + result, bufsize - result, | ||
151 | &wss->bcast); | ||
152 | result += scnprintf(buf + result, bufsize - result, | ||
153 | " 0x%02x %u ", wss->hash, wss->secure_status); | ||
154 | result += wlp_wss_key_print(buf + result, bufsize - result, | ||
155 | wss->master_key); | ||
156 | result += scnprintf(buf + result, bufsize - result, " 0x%02x ", | ||
157 | wss->tag); | ||
158 | result += uwb_mac_addr_print(buf + result, bufsize - result, | ||
159 | &wss->virtual_addr); | ||
160 | result += scnprintf(buf + result, bufsize - result, " %s", wss->name); | ||
161 | result += scnprintf(buf + result, bufsize - result, | ||
162 | "\n\n#WSSID\n#WSS broadcast address\n" | ||
163 | "#WSS hash\n#WSS secure status\n" | ||
164 | "#WSS master key\n#WSS local tag\n" | ||
165 | "#WSS local virtual EUI-48\n#WSS name\n"); | ||
166 | return result; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * Show which WSS is activated. | ||
171 | */ | ||
172 | ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf) | ||
173 | { | ||
174 | int result = 0; | ||
175 | |||
176 | if (mutex_lock_interruptible(&wss->mutex)) | ||
177 | goto out; | ||
178 | if (wss->state >= WLP_WSS_STATE_ACTIVE) | ||
179 | result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE); | ||
180 | else | ||
181 | result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n"); | ||
182 | result += scnprintf(buf + result, PAGE_SIZE - result, | ||
183 | "\n\n" | ||
184 | "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT " | ||
185 | "NAME #create new WSS\n" | ||
186 | "# echo WSSID [DEV ADDR] #enroll in and activate " | ||
187 | "existing WSS, can request registrar\n" | ||
188 | "#\n" | ||
189 | "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n" | ||
190 | "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n" | ||
191 | "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n" | ||
192 | "# NAME is the text string identifying the WSS\n" | ||
193 | "# DEV ADDR is the device address of neighbor " | ||
194 | "that should be registrar. Eg. 32:AB\n"); | ||
195 | |||
196 | mutex_unlock(&wss->mutex); | ||
197 | out: | ||
198 | return result; | ||
199 | |||
200 | } | ||
201 | EXPORT_SYMBOL_GPL(wlp_wss_activate_show); | ||
202 | |||
203 | /** | ||
204 | * Create/activate a new WSS or enroll/activate in neighboring WSS | ||
205 | * | ||
206 | * The user can provide the WSSID of a WSS in which it wants to enroll. | ||
207 | * Only the WSSID is necessary if the WSS have been discovered before. If | ||
208 | * the WSS has not been discovered before, or the user wants to use a | ||
209 | * particular neighbor as its registrar, then the user can also provide a | ||
210 | * device address or the neighbor that will be used as registrar. | ||
211 | * | ||
212 | * A new WSS is created when the user provides a WSSID, secure status, and | ||
213 | * WSS name. | ||
214 | */ | ||
215 | ssize_t wlp_wss_activate_store(struct wlp_wss *wss, | ||
216 | const char *buf, size_t size) | ||
217 | { | ||
218 | ssize_t result = -EINVAL; | ||
219 | struct wlp_uuid wssid; | ||
220 | struct uwb_dev_addr dev; | ||
221 | struct uwb_dev_addr bcast = {.data = {0xff, 0xff} }; | ||
222 | char name[65]; | ||
223 | unsigned sec_status, accept; | ||
224 | memset(name, 0, sizeof(name)); | ||
225 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
226 | "%02hhx %02hhx %02hhx %02hhx " | ||
227 | "%02hhx %02hhx %02hhx %02hhx " | ||
228 | "%02hhx %02hhx %02hhx %02hhx " | ||
229 | "%02hhx:%02hhx", | ||
230 | &wssid.data[0] , &wssid.data[1], | ||
231 | &wssid.data[2] , &wssid.data[3], | ||
232 | &wssid.data[4] , &wssid.data[5], | ||
233 | &wssid.data[6] , &wssid.data[7], | ||
234 | &wssid.data[8] , &wssid.data[9], | ||
235 | &wssid.data[10], &wssid.data[11], | ||
236 | &wssid.data[12], &wssid.data[13], | ||
237 | &wssid.data[14], &wssid.data[15], | ||
238 | &dev.data[1], &dev.data[0]); | ||
239 | if (result == 16 || result == 17) { | ||
240 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
241 | "%02hhx %02hhx %02hhx %02hhx " | ||
242 | "%02hhx %02hhx %02hhx %02hhx " | ||
243 | "%02hhx %02hhx %02hhx %02hhx " | ||
244 | "%u %u %64c", | ||
245 | &wssid.data[0] , &wssid.data[1], | ||
246 | &wssid.data[2] , &wssid.data[3], | ||
247 | &wssid.data[4] , &wssid.data[5], | ||
248 | &wssid.data[6] , &wssid.data[7], | ||
249 | &wssid.data[8] , &wssid.data[9], | ||
250 | &wssid.data[10], &wssid.data[11], | ||
251 | &wssid.data[12], &wssid.data[13], | ||
252 | &wssid.data[14], &wssid.data[15], | ||
253 | &sec_status, &accept, name); | ||
254 | if (result == 16) | ||
255 | result = wlp_wss_enroll_activate(wss, &wssid, &bcast); | ||
256 | else if (result == 19) { | ||
257 | sec_status = sec_status == 0 ? 0 : 1; | ||
258 | accept = accept == 0 ? 0 : 1; | ||
259 | /* We read name using %c, so the newline needs to be | ||
260 | * removed */ | ||
261 | if (strlen(name) != sizeof(name) - 1) | ||
262 | name[strlen(name) - 1] = '\0'; | ||
263 | result = wlp_wss_create_activate(wss, &wssid, name, | ||
264 | sec_status, accept); | ||
265 | } else | ||
266 | result = -EINVAL; | ||
267 | } else if (result == 18) | ||
268 | result = wlp_wss_enroll_activate(wss, &wssid, &dev); | ||
269 | else | ||
270 | result = -EINVAL; | ||
271 | return result < 0 ? result : size; | ||
272 | } | ||
273 | EXPORT_SYMBOL_GPL(wlp_wss_activate_store); | ||
274 | |||
275 | /** | ||
276 | * Show the UUID of this host | ||
277 | */ | ||
278 | ssize_t wlp_uuid_show(struct wlp *wlp, char *buf) | ||
279 | { | ||
280 | ssize_t result = 0; | ||
281 | |||
282 | mutex_lock(&wlp->mutex); | ||
283 | result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid); | ||
284 | buf[result++] = '\n'; | ||
285 | mutex_unlock(&wlp->mutex); | ||
286 | return result; | ||
287 | } | ||
288 | EXPORT_SYMBOL_GPL(wlp_uuid_show); | ||
289 | |||
290 | /** | ||
291 | * Store a new UUID for this host | ||
292 | * | ||
293 | * According to the spec this should be encoded as an octet string in the | ||
294 | * order the octets are shown in string representation in RFC 4122 (WLP | ||
295 | * 0.99 [Table 6]) | ||
296 | * | ||
297 | * We do not check value provided by user. | ||
298 | */ | ||
299 | ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size) | ||
300 | { | ||
301 | ssize_t result; | ||
302 | struct wlp_uuid uuid; | ||
303 | |||
304 | mutex_lock(&wlp->mutex); | ||
305 | result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx " | ||
306 | "%02hhx %02hhx %02hhx %02hhx " | ||
307 | "%02hhx %02hhx %02hhx %02hhx " | ||
308 | "%02hhx %02hhx %02hhx %02hhx ", | ||
309 | &uuid.data[0] , &uuid.data[1], | ||
310 | &uuid.data[2] , &uuid.data[3], | ||
311 | &uuid.data[4] , &uuid.data[5], | ||
312 | &uuid.data[6] , &uuid.data[7], | ||
313 | &uuid.data[8] , &uuid.data[9], | ||
314 | &uuid.data[10], &uuid.data[11], | ||
315 | &uuid.data[12], &uuid.data[13], | ||
316 | &uuid.data[14], &uuid.data[15]); | ||
317 | if (result != 16) { | ||
318 | result = -EINVAL; | ||
319 | goto error; | ||
320 | } | ||
321 | wlp->uuid = uuid; | ||
322 | error: | ||
323 | mutex_unlock(&wlp->mutex); | ||
324 | return result < 0 ? result : size; | ||
325 | } | ||
326 | EXPORT_SYMBOL_GPL(wlp_uuid_store); | ||
327 | |||
328 | /** | ||
329 | * Show contents of members of device information structure | ||
330 | */ | ||
331 | #define wlp_dev_info_show(type) \ | ||
332 | ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \ | ||
333 | { \ | ||
334 | ssize_t result = 0; \ | ||
335 | mutex_lock(&wlp->mutex); \ | ||
336 | if (wlp->dev_info == NULL) { \ | ||
337 | result = __wlp_setup_device_info(wlp); \ | ||
338 | if (result < 0) \ | ||
339 | goto out; \ | ||
340 | } \ | ||
341 | result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\ | ||
342 | out: \ | ||
343 | mutex_unlock(&wlp->mutex); \ | ||
344 | return result; \ | ||
345 | } \ | ||
346 | EXPORT_SYMBOL_GPL(wlp_dev_##type##_show); | ||
347 | |||
348 | wlp_dev_info_show(name) | ||
349 | wlp_dev_info_show(model_name) | ||
350 | wlp_dev_info_show(model_nr) | ||
351 | wlp_dev_info_show(manufacturer) | ||
352 | wlp_dev_info_show(serial) | ||
353 | |||
354 | /** | ||
355 | * Store contents of members of device information structure | ||
356 | */ | ||
357 | #define wlp_dev_info_store(type, len) \ | ||
358 | ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\ | ||
359 | { \ | ||
360 | ssize_t result; \ | ||
361 | char format[10]; \ | ||
362 | mutex_lock(&wlp->mutex); \ | ||
363 | if (wlp->dev_info == NULL) { \ | ||
364 | result = __wlp_alloc_device_info(wlp); \ | ||
365 | if (result < 0) \ | ||
366 | goto out; \ | ||
367 | } \ | ||
368 | memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \ | ||
369 | sprintf(format, "%%%uc", len); \ | ||
370 | result = sscanf(buf, format, wlp->dev_info->type); \ | ||
371 | out: \ | ||
372 | mutex_unlock(&wlp->mutex); \ | ||
373 | return result < 0 ? result : size; \ | ||
374 | } \ | ||
375 | EXPORT_SYMBOL_GPL(wlp_dev_##type##_store); | ||
376 | |||
377 | wlp_dev_info_store(name, 32) | ||
378 | wlp_dev_info_store(manufacturer, 64) | ||
379 | wlp_dev_info_store(model_name, 32) | ||
380 | wlp_dev_info_store(model_nr, 32) | ||
381 | wlp_dev_info_store(serial, 32) | ||
382 | |||
383 | static | ||
384 | const char *__wlp_dev_category[] = { | ||
385 | [WLP_DEV_CAT_COMPUTER] = "Computer", | ||
386 | [WLP_DEV_CAT_INPUT] = "Input device", | ||
387 | [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or " | ||
388 | "Copier", | ||
389 | [WLP_DEV_CAT_CAMERA] = "Camera", | ||
390 | [WLP_DEV_CAT_STORAGE] = "Storage Network", | ||
391 | [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure", | ||
392 | [WLP_DEV_CAT_DISPLAY] = "Display", | ||
393 | [WLP_DEV_CAT_MULTIM] = "Multimedia device", | ||
394 | [WLP_DEV_CAT_GAMING] = "Gaming device", | ||
395 | [WLP_DEV_CAT_TELEPHONE] = "Telephone", | ||
396 | [WLP_DEV_CAT_OTHER] = "Other", | ||
397 | }; | ||
398 | |||
399 | static | ||
400 | const char *wlp_dev_category_str(unsigned cat) | ||
401 | { | ||
402 | if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE) | ||
403 | || cat == WLP_DEV_CAT_OTHER) | ||
404 | return __wlp_dev_category[cat]; | ||
405 | return "unknown category"; | ||
406 | } | ||
407 | |||
408 | ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf) | ||
409 | { | ||
410 | ssize_t result = 0; | ||
411 | mutex_lock(&wlp->mutex); | ||
412 | if (wlp->dev_info == NULL) { | ||
413 | result = __wlp_setup_device_info(wlp); | ||
414 | if (result < 0) | ||
415 | goto out; | ||
416 | } | ||
417 | result = scnprintf(buf, PAGE_SIZE, "%s\n", | ||
418 | wlp_dev_category_str(wlp->dev_info->prim_dev_type.category)); | ||
419 | out: | ||
420 | mutex_unlock(&wlp->mutex); | ||
421 | return result; | ||
422 | } | ||
423 | EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show); | ||
424 | |||
425 | ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf, | ||
426 | size_t size) | ||
427 | { | ||
428 | ssize_t result; | ||
429 | u16 cat; | ||
430 | mutex_lock(&wlp->mutex); | ||
431 | if (wlp->dev_info == NULL) { | ||
432 | result = __wlp_alloc_device_info(wlp); | ||
433 | if (result < 0) | ||
434 | goto out; | ||
435 | } | ||
436 | result = sscanf(buf, "%hu", &cat); | ||
437 | if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE) | ||
438 | || cat == WLP_DEV_CAT_OTHER) | ||
439 | wlp->dev_info->prim_dev_type.category = cat; | ||
440 | else | ||
441 | result = -EINVAL; | ||
442 | out: | ||
443 | mutex_unlock(&wlp->mutex); | ||
444 | return result < 0 ? result : size; | ||
445 | } | ||
446 | EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store); | ||
447 | |||
448 | ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf) | ||
449 | { | ||
450 | ssize_t result = 0; | ||
451 | mutex_lock(&wlp->mutex); | ||
452 | if (wlp->dev_info == NULL) { | ||
453 | result = __wlp_setup_device_info(wlp); | ||
454 | if (result < 0) | ||
455 | goto out; | ||
456 | } | ||
457 | result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n", | ||
458 | wlp->dev_info->prim_dev_type.OUI[0], | ||
459 | wlp->dev_info->prim_dev_type.OUI[1], | ||
460 | wlp->dev_info->prim_dev_type.OUI[2]); | ||
461 | out: | ||
462 | mutex_unlock(&wlp->mutex); | ||
463 | return result; | ||
464 | } | ||
465 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show); | ||
466 | |||
467 | ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size) | ||
468 | { | ||
469 | ssize_t result; | ||
470 | u8 OUI[3]; | ||
471 | mutex_lock(&wlp->mutex); | ||
472 | if (wlp->dev_info == NULL) { | ||
473 | result = __wlp_alloc_device_info(wlp); | ||
474 | if (result < 0) | ||
475 | goto out; | ||
476 | } | ||
477 | result = sscanf(buf, "%hhx:%hhx:%hhx", | ||
478 | &OUI[0], &OUI[1], &OUI[2]); | ||
479 | if (result != 3) { | ||
480 | result = -EINVAL; | ||
481 | goto out; | ||
482 | } else | ||
483 | memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI)); | ||
484 | out: | ||
485 | mutex_unlock(&wlp->mutex); | ||
486 | return result < 0 ? result : size; | ||
487 | } | ||
488 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store); | ||
489 | |||
490 | |||
491 | ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf) | ||
492 | { | ||
493 | ssize_t result = 0; | ||
494 | mutex_lock(&wlp->mutex); | ||
495 | if (wlp->dev_info == NULL) { | ||
496 | result = __wlp_setup_device_info(wlp); | ||
497 | if (result < 0) | ||
498 | goto out; | ||
499 | } | ||
500 | result = scnprintf(buf, PAGE_SIZE, "%u\n", | ||
501 | wlp->dev_info->prim_dev_type.OUIsubdiv); | ||
502 | out: | ||
503 | mutex_unlock(&wlp->mutex); | ||
504 | return result; | ||
505 | } | ||
506 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show); | ||
507 | |||
508 | ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf, | ||
509 | size_t size) | ||
510 | { | ||
511 | ssize_t result; | ||
512 | unsigned sub; | ||
513 | u8 max_sub = ~0; | ||
514 | mutex_lock(&wlp->mutex); | ||
515 | if (wlp->dev_info == NULL) { | ||
516 | result = __wlp_alloc_device_info(wlp); | ||
517 | if (result < 0) | ||
518 | goto out; | ||
519 | } | ||
520 | result = sscanf(buf, "%u", &sub); | ||
521 | if (sub <= max_sub) | ||
522 | wlp->dev_info->prim_dev_type.OUIsubdiv = sub; | ||
523 | else | ||
524 | result = -EINVAL; | ||
525 | out: | ||
526 | mutex_unlock(&wlp->mutex); | ||
527 | return result < 0 ? result : size; | ||
528 | } | ||
529 | EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store); | ||
530 | |||
531 | ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf) | ||
532 | { | ||
533 | ssize_t result = 0; | ||
534 | mutex_lock(&wlp->mutex); | ||
535 | if (wlp->dev_info == NULL) { | ||
536 | result = __wlp_setup_device_info(wlp); | ||
537 | if (result < 0) | ||
538 | goto out; | ||
539 | } | ||
540 | result = scnprintf(buf, PAGE_SIZE, "%u\n", | ||
541 | wlp->dev_info->prim_dev_type.subID); | ||
542 | out: | ||
543 | mutex_unlock(&wlp->mutex); | ||
544 | return result; | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show); | ||
547 | |||
548 | ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf, | ||
549 | size_t size) | ||
550 | { | ||
551 | ssize_t result; | ||
552 | unsigned sub; | ||
553 | __le16 max_sub = ~0; | ||
554 | mutex_lock(&wlp->mutex); | ||
555 | if (wlp->dev_info == NULL) { | ||
556 | result = __wlp_alloc_device_info(wlp); | ||
557 | if (result < 0) | ||
558 | goto out; | ||
559 | } | ||
560 | result = sscanf(buf, "%u", &sub); | ||
561 | if (sub <= max_sub) | ||
562 | wlp->dev_info->prim_dev_type.subID = sub; | ||
563 | else | ||
564 | result = -EINVAL; | ||
565 | out: | ||
566 | mutex_unlock(&wlp->mutex); | ||
567 | return result < 0 ? result : size; | ||
568 | } | ||
569 | EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store); | ||
570 | |||
571 | /** | ||
572 | * Subsystem implementation for interaction with individual WSS via sysfs | ||
573 | * | ||
574 | * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt | ||
575 | */ | ||
576 | |||
577 | #define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj) | ||
578 | #define attr_to_wlp_wss_attr(_attr) \ | ||
579 | container_of(_attr, struct wlp_wss_attribute, attr) | ||
580 | |||
581 | /** | ||
582 | * Sysfs subsystem: forward read calls | ||
583 | * | ||
584 | * Sysfs operation for forwarding read call to the show method of the | ||
585 | * attribute owner | ||
586 | */ | ||
587 | static | ||
588 | ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr, | ||
589 | char *buf) | ||
590 | { | ||
591 | struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr); | ||
592 | struct wlp_wss *wss = kobj_to_wlp_wss(kobj); | ||
593 | ssize_t ret = -EIO; | ||
594 | |||
595 | if (wss_attr->show) | ||
596 | ret = wss_attr->show(wss, buf); | ||
597 | return ret; | ||
598 | } | ||
599 | /** | ||
600 | * Sysfs subsystem: forward write calls | ||
601 | * | ||
602 | * Sysfs operation for forwarding write call to the store method of the | ||
603 | * attribute owner | ||
604 | */ | ||
605 | static | ||
606 | ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr, | ||
607 | const char *buf, size_t count) | ||
608 | { | ||
609 | struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr); | ||
610 | struct wlp_wss *wss = kobj_to_wlp_wss(kobj); | ||
611 | ssize_t ret = -EIO; | ||
612 | |||
613 | if (wss_attr->store) | ||
614 | ret = wss_attr->store(wss, buf, count); | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static | ||
619 | struct sysfs_ops wss_sysfs_ops = { | ||
620 | .show = wlp_wss_attr_show, | ||
621 | .store = wlp_wss_attr_store, | ||
622 | }; | ||
623 | |||
624 | struct kobj_type wss_ktype = { | ||
625 | .release = wlp_wss_release, | ||
626 | .sysfs_ops = &wss_sysfs_ops, | ||
627 | }; | ||
628 | |||
629 | |||
630 | /** | ||
631 | * Sysfs files for individual WSS | ||
632 | */ | ||
633 | |||
634 | /** | ||
635 | * Print static properties of this WSS | ||
636 | * | ||
637 | * The name of a WSS may not be null teminated. It's max size is 64 bytes | ||
638 | * so we copy it to a larger array just to make sure we print sane data. | ||
639 | */ | ||
640 | static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf) | ||
641 | { | ||
642 | int result = 0; | ||
643 | |||
644 | if (mutex_lock_interruptible(&wss->mutex)) | ||
645 | goto out; | ||
646 | result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE); | ||
647 | mutex_unlock(&wss->mutex); | ||
648 | out: | ||
649 | return result; | ||
650 | } | ||
651 | WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL); | ||
652 | |||
653 | /** | ||
654 | * Print all connected members of this WSS | ||
655 | * The EDA cache contains all members of WSS neighborhood. | ||
656 | */ | ||
657 | static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf) | ||
658 | { | ||
659 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
660 | return wlp_eda_show(wlp, buf); | ||
661 | } | ||
662 | WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL); | ||
663 | |||
664 | static | ||
665 | const char *__wlp_strstate[] = { | ||
666 | "none", | ||
667 | "partially enrolled", | ||
668 | "enrolled", | ||
669 | "active", | ||
670 | "connected", | ||
671 | }; | ||
672 | |||
673 | static const char *wlp_wss_strstate(unsigned state) | ||
674 | { | ||
675 | if (state >= ARRAY_SIZE(__wlp_strstate)) | ||
676 | return "unknown state"; | ||
677 | return __wlp_strstate[state]; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Print current state of this WSS | ||
682 | */ | ||
683 | static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf) | ||
684 | { | ||
685 | int result = 0; | ||
686 | |||
687 | if (mutex_lock_interruptible(&wss->mutex)) | ||
688 | goto out; | ||
689 | result = scnprintf(buf, PAGE_SIZE, "%s\n", | ||
690 | wlp_wss_strstate(wss->state)); | ||
691 | mutex_unlock(&wss->mutex); | ||
692 | out: | ||
693 | return result; | ||
694 | } | ||
695 | WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL); | ||
696 | |||
697 | |||
698 | static | ||
699 | struct attribute *wss_attrs[] = { | ||
700 | &wss_attr_properties.attr, | ||
701 | &wss_attr_members.attr, | ||
702 | &wss_attr_state.attr, | ||
703 | NULL, | ||
704 | }; | ||
705 | |||
706 | struct attribute_group wss_attr_group = { | ||
707 | .name = NULL, /* we want them in the same directory */ | ||
708 | .attrs = wss_attrs, | ||
709 | }; | ||
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c new file mode 100644 index 000000000000..c701bd1a2887 --- /dev/null +++ b/drivers/uwb/wlp/txrx.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Message exchange infrastructure | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: Docs | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/wlp.h> | ||
29 | #define D_LOCAL 5 | ||
30 | #include <linux/uwb/debug.h> | ||
31 | #include "wlp-internal.h" | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Direct incoming association msg to correct parsing routine | ||
36 | * | ||
37 | * We only expect D1, E1, C1, C3 messages as new. All other incoming | ||
38 | * association messages should form part of an established session that is | ||
39 | * handled elsewhere. | ||
40 | * The handling of these messages often require calling sleeping functions | ||
41 | * - this cannot be done in interrupt context. We use the kernel's | ||
42 | * workqueue to handle these messages. | ||
43 | */ | ||
44 | static | ||
45 | void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb, | ||
46 | struct uwb_dev_addr *src) | ||
47 | { | ||
48 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
49 | struct wlp_frame_assoc *assoc = (void *) skb->data; | ||
50 | struct wlp_assoc_frame_ctx *frame_ctx; | ||
51 | d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb); | ||
52 | frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC); | ||
53 | if (frame_ctx == NULL) { | ||
54 | dev_err(dev, "WLP: Unable to allocate memory for association " | ||
55 | "frame handling.\n"); | ||
56 | kfree_skb(skb); | ||
57 | goto out; | ||
58 | } | ||
59 | frame_ctx->wlp = wlp; | ||
60 | frame_ctx->skb = skb; | ||
61 | frame_ctx->src = *src; | ||
62 | switch (assoc->type) { | ||
63 | case WLP_ASSOC_D1: | ||
64 | d_printf(5, dev, "Received a D1 frame.\n"); | ||
65 | INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame); | ||
66 | schedule_work(&frame_ctx->ws); | ||
67 | break; | ||
68 | case WLP_ASSOC_E1: | ||
69 | d_printf(5, dev, "Received a E1 frame. FIXME?\n"); | ||
70 | kfree_skb(skb); /* Temporary until we handle it */ | ||
71 | kfree(frame_ctx); /* Temporary until we handle it */ | ||
72 | break; | ||
73 | case WLP_ASSOC_C1: | ||
74 | d_printf(5, dev, "Received a C1 frame.\n"); | ||
75 | INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame); | ||
76 | schedule_work(&frame_ctx->ws); | ||
77 | break; | ||
78 | case WLP_ASSOC_C3: | ||
79 | d_printf(5, dev, "Received a C3 frame.\n"); | ||
80 | INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame); | ||
81 | schedule_work(&frame_ctx->ws); | ||
82 | break; | ||
83 | default: | ||
84 | dev_err(dev, "Received unexpected association frame. " | ||
85 | "Type = %d \n", assoc->type); | ||
86 | kfree_skb(skb); | ||
87 | kfree(frame_ctx); | ||
88 | break; | ||
89 | } | ||
90 | out: | ||
91 | d_fnend(5, dev, "wlp %p\n", wlp); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Process incoming association frame | ||
96 | * | ||
97 | * Although it could be possible to deal with some incoming association | ||
98 | * messages without creating a new session we are keeping things simple. We | ||
99 | * do not accept new association messages if there is a session in progress | ||
100 | * and the messages do not belong to that session. | ||
101 | * | ||
102 | * If an association message arrives that causes the creation of a session | ||
103 | * (WLP_ASSOC_E1) while we are in the process of creating a session then we | ||
104 | * rely on the neighbor mutex to protect the data. That is, the new session | ||
105 | * will not be started until the previous is completed. | ||
106 | */ | ||
107 | static | ||
108 | void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb, | ||
109 | struct uwb_dev_addr *src) | ||
110 | { | ||
111 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
112 | struct wlp_frame_assoc *assoc = (void *) skb->data; | ||
113 | struct wlp_session *session = wlp->session; | ||
114 | u8 version; | ||
115 | d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb); | ||
116 | |||
117 | if (wlp_get_version(wlp, &assoc->version, &version, | ||
118 | sizeof(assoc->version)) < 0) | ||
119 | goto error; | ||
120 | if (version != WLP_VERSION) { | ||
121 | dev_err(dev, "Unsupported WLP version in association " | ||
122 | "message.\n"); | ||
123 | goto error; | ||
124 | } | ||
125 | if (session != NULL) { | ||
126 | /* Function that created this session is still holding the | ||
127 | * &wlp->mutex to protect this session. */ | ||
128 | if (assoc->type == session->exp_message || | ||
129 | assoc->type == WLP_ASSOC_F0) { | ||
130 | if (!memcmp(&session->neighbor_addr, src, | ||
131 | sizeof(*src))) { | ||
132 | session->data = skb; | ||
133 | (session->cb)(wlp); | ||
134 | } else { | ||
135 | dev_err(dev, "Received expected message from " | ||
136 | "unexpected source. Expected message " | ||
137 | "%d or F0 from %02x:%02x, but received " | ||
138 | "it from %02x:%02x. Dropping.\n", | ||
139 | session->exp_message, | ||
140 | session->neighbor_addr.data[1], | ||
141 | session->neighbor_addr.data[0], | ||
142 | src->data[1], src->data[0]); | ||
143 | goto error; | ||
144 | } | ||
145 | } else { | ||
146 | dev_err(dev, "Association already in progress. " | ||
147 | "Dropping.\n"); | ||
148 | goto error; | ||
149 | } | ||
150 | } else { | ||
151 | wlp_direct_assoc_frame(wlp, skb, src); | ||
152 | } | ||
153 | d_fnend(5, dev, "wlp %p\n", wlp); | ||
154 | return; | ||
155 | error: | ||
156 | kfree_skb(skb); | ||
157 | d_fnend(5, dev, "wlp %p\n", wlp); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * Verify incoming frame is from connected neighbor, prep to pass to WLP client | ||
162 | * | ||
163 | * Verification proceeds according to WLP 0.99 [7.3.1]. The source address | ||
164 | * is used to determine which neighbor is sending the frame and the WSS tag | ||
165 | * is used to know to which WSS the frame belongs (we only support one WSS | ||
166 | * so this test is straight forward). | ||
167 | * With the WSS found we need to ensure that we are connected before | ||
168 | * allowing the exchange of data frames. | ||
169 | */ | ||
170 | static | ||
171 | int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb, | ||
172 | struct uwb_dev_addr *src) | ||
173 | { | ||
174 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
175 | int result = -EINVAL; | ||
176 | struct wlp_eda_node eda_entry; | ||
177 | struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data; | ||
178 | |||
179 | d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb); | ||
180 | /*verify*/ | ||
181 | result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry); | ||
182 | if (result < 0) { | ||
183 | if (printk_ratelimit()) | ||
184 | dev_err(dev, "WLP: Incoming frame is from unknown " | ||
185 | "neighbor %02x:%02x.\n", src->data[1], | ||
186 | src->data[0]); | ||
187 | goto out; | ||
188 | } | ||
189 | if (hdr->tag != eda_entry.tag) { | ||
190 | if (printk_ratelimit()) | ||
191 | dev_err(dev, "WLP: Tag of incoming frame from " | ||
192 | "%02x:%02x does not match expected tag. " | ||
193 | "Received 0x%02x, expected 0x%02x. \n", | ||
194 | src->data[1], src->data[0], hdr->tag, | ||
195 | eda_entry.tag); | ||
196 | result = -EINVAL; | ||
197 | goto out; | ||
198 | } | ||
199 | if (eda_entry.state != WLP_WSS_CONNECTED) { | ||
200 | if (printk_ratelimit()) | ||
201 | dev_err(dev, "WLP: Incoming frame from " | ||
202 | "%02x:%02x does is not from connected WSS.\n", | ||
203 | src->data[1], src->data[0]); | ||
204 | result = -EINVAL; | ||
205 | goto out; | ||
206 | } | ||
207 | /*prep*/ | ||
208 | skb_pull(skb, sizeof(*hdr)); | ||
209 | out: | ||
210 | d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result); | ||
211 | return result; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * Receive a WLP frame from device | ||
216 | * | ||
217 | * @returns: 1 if calling function should free the skb | ||
218 | * 0 if it successfully handled skb and freed it | ||
219 | * 0 if error occured, will free skb in this case | ||
220 | */ | ||
221 | int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb, | ||
222 | struct uwb_dev_addr *src) | ||
223 | { | ||
224 | unsigned len = skb->len; | ||
225 | void *ptr = skb->data; | ||
226 | struct wlp_frame_hdr *hdr; | ||
227 | int result = 0; | ||
228 | |||
229 | d_fnstart(6, dev, "skb (%p), len (%u)\n", skb, len); | ||
230 | if (len < sizeof(*hdr)) { | ||
231 | dev_err(dev, "Not enough data to parse WLP header.\n"); | ||
232 | result = -EINVAL; | ||
233 | goto out; | ||
234 | } | ||
235 | hdr = ptr; | ||
236 | d_dump(6, dev, hdr, sizeof(*hdr)); | ||
237 | if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) { | ||
238 | dev_err(dev, "Not a WLP frame type.\n"); | ||
239 | result = -EINVAL; | ||
240 | goto out; | ||
241 | } | ||
242 | switch (hdr->type) { | ||
243 | case WLP_FRAME_STANDARD: | ||
244 | if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) { | ||
245 | dev_err(dev, "Not enough data to parse Standard " | ||
246 | "WLP header.\n"); | ||
247 | goto out; | ||
248 | } | ||
249 | result = wlp_verify_prep_rx_frame(wlp, skb, src); | ||
250 | if (result < 0) { | ||
251 | if (printk_ratelimit()) | ||
252 | dev_err(dev, "WLP: Verification of frame " | ||
253 | "from neighbor %02x:%02x failed.\n", | ||
254 | src->data[1], src->data[0]); | ||
255 | goto out; | ||
256 | } | ||
257 | result = 1; | ||
258 | break; | ||
259 | case WLP_FRAME_ABBREVIATED: | ||
260 | dev_err(dev, "Abbreviated frame received. FIXME?\n"); | ||
261 | kfree_skb(skb); | ||
262 | break; | ||
263 | case WLP_FRAME_CONTROL: | ||
264 | dev_err(dev, "Control frame received. FIXME?\n"); | ||
265 | kfree_skb(skb); | ||
266 | break; | ||
267 | case WLP_FRAME_ASSOCIATION: | ||
268 | if (len < sizeof(struct wlp_frame_assoc)) { | ||
269 | dev_err(dev, "Not enough data to parse Association " | ||
270 | "WLP header.\n"); | ||
271 | goto out; | ||
272 | } | ||
273 | d_printf(5, dev, "Association frame received.\n"); | ||
274 | wlp_receive_assoc_frame(wlp, skb, src); | ||
275 | break; | ||
276 | default: | ||
277 | dev_err(dev, "Invalid frame received.\n"); | ||
278 | result = -EINVAL; | ||
279 | break; | ||
280 | } | ||
281 | out: | ||
282 | if (result < 0) { | ||
283 | kfree_skb(skb); | ||
284 | result = 0; | ||
285 | } | ||
286 | d_fnend(6, dev, "skb (%p)\n", skb); | ||
287 | return result; | ||
288 | } | ||
289 | EXPORT_SYMBOL_GPL(wlp_receive_frame); | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Verify frame from network stack, prepare for further transmission | ||
294 | * | ||
295 | * @skb: the socket buffer that needs to be prepared for transmission (it | ||
296 | * is in need of a WLP header). If this is a broadcast frame we take | ||
297 | * over the entire transmission. | ||
298 | * If it is a unicast the WSS connection should already be established | ||
299 | * and transmission will be done by the calling function. | ||
300 | * @dst: On return this will contain the device address to which the | ||
301 | * frame is destined. | ||
302 | * @returns: 0 on success no tx : WLP header sucessfully applied to skb buffer, | ||
303 | * calling function can proceed with tx | ||
304 | * 1 on success with tx : WLP will take over transmission of this | ||
305 | * frame | ||
306 | * <0 on error | ||
307 | * | ||
308 | * The network stack (WLP client) is attempting to transmit a frame. We can | ||
309 | * only transmit data if a local WSS is at least active (connection will be | ||
310 | * done here if this is a broadcast frame and neighbor also has the WSS | ||
311 | * active). | ||
312 | * | ||
313 | * The frame can be either broadcast or unicast. Broadcast in a WSS is | ||
314 | * supported via multicast, but we don't support multicast yet (until | ||
315 | * devices start to support MAB IEs). If a broadcast frame needs to be | ||
316 | * transmitted it is treated as a unicast frame to each neighbor. In this | ||
317 | * case the WLP takes over transmission of the skb and returns 1 | ||
318 | * to the caller to indicate so. Also, in this case, if a neighbor has the | ||
319 | * same WSS activated but is not connected then the WSS connection will be | ||
320 | * done at this time. The neighbor's virtual address will be learned at | ||
321 | * this time. | ||
322 | * | ||
323 | * The destination address in a unicast frame is the virtual address of the | ||
324 | * neighbor. This address only becomes known when a WSS connection is | ||
325 | * established. We thus rely on a broadcast frame to trigger the setup of | ||
326 | * WSS connections to all neighbors before we are able to send unicast | ||
327 | * frames to them. This seems reasonable as IP would usually use ARP first | ||
328 | * before any unicast frames are sent. | ||
329 | * | ||
330 | * If we are already connected to the neighbor (neighbor's virtual address | ||
331 | * is known) we just prepare the WLP header and the caller will continue to | ||
332 | * send the frame. | ||
333 | * | ||
334 | * A failure in this function usually indicates something that cannot be | ||
335 | * fixed automatically. So, if this function fails (@return < 0) the calling | ||
336 | * function should not retry to send the frame as it will very likely keep | ||
337 | * failing. | ||
338 | * | ||
339 | */ | ||
340 | int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, | ||
341 | struct sk_buff *skb, struct uwb_dev_addr *dst) | ||
342 | { | ||
343 | int result = -EINVAL; | ||
344 | struct ethhdr *eth_hdr = (void *) skb->data; | ||
345 | |||
346 | d_fnstart(6, dev, "wlp (%p), skb (%p) \n", wlp, skb); | ||
347 | if (is_broadcast_ether_addr(eth_hdr->h_dest)) { | ||
348 | d_printf(6, dev, "WLP: handling broadcast frame. \n"); | ||
349 | result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb); | ||
350 | if (result < 0) { | ||
351 | if (printk_ratelimit()) | ||
352 | dev_err(dev, "Unable to handle broadcast " | ||
353 | "frame from WLP client.\n"); | ||
354 | goto out; | ||
355 | } | ||
356 | dev_kfree_skb_irq(skb); | ||
357 | result = 1; | ||
358 | /* Frame will be transmitted by WLP. */ | ||
359 | } else { | ||
360 | d_printf(6, dev, "WLP: handling unicast frame. \n"); | ||
361 | result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst, | ||
362 | wlp_wss_prep_hdr, skb); | ||
363 | if (unlikely(result < 0)) { | ||
364 | if (printk_ratelimit()) | ||
365 | dev_err(dev, "Unable to prepare " | ||
366 | "skb for transmission. \n"); | ||
367 | goto out; | ||
368 | } | ||
369 | } | ||
370 | out: | ||
371 | d_fnend(6, dev, "wlp (%p), skb (%p). result = %d \n", wlp, skb, result); | ||
372 | return result; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame); | ||
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h new file mode 100644 index 000000000000..1c94fabfb1a7 --- /dev/null +++ b/drivers/uwb/wlp/wlp-internal.h | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * Internal API | ||
4 | * | ||
5 | * Copyright (C) 2007 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __WLP_INTERNAL_H__ | ||
25 | #define __WLP_INTERNAL_H__ | ||
26 | |||
27 | /** | ||
28 | * State of WSS connection | ||
29 | * | ||
30 | * A device needs to connect to a neighbor in an activated WSS before data | ||
31 | * can be transmitted. The spec also distinguishes between a new connection | ||
32 | * attempt and a connection attempt after previous connection attempts. The | ||
33 | * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99 | ||
34 | * [7.2.6] | ||
35 | */ | ||
36 | enum wlp_wss_connect { | ||
37 | WLP_WSS_UNCONNECTED = 0, | ||
38 | WLP_WSS_CONNECTED, | ||
39 | WLP_WSS_CONNECT_FAILED, | ||
40 | }; | ||
41 | |||
42 | extern struct kobj_type wss_ktype; | ||
43 | extern struct attribute_group wss_attr_group; | ||
44 | |||
45 | extern int uwb_rc_ie_add(struct uwb_rc *, const struct uwb_ie_hdr *, size_t); | ||
46 | extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie); | ||
47 | |||
48 | |||
49 | /* This should be changed to a dynamic array where entries are sorted | ||
50 | * by eth_addr and search is done in a binary form | ||
51 | * | ||
52 | * Although thinking twice about it: this technologie's maximum reach | ||
53 | * is 10 meters...unless you want to pack too much stuff in around | ||
54 | * your radio controller/WLP device, the list will probably not be | ||
55 | * too big. | ||
56 | * | ||
57 | * In any case, there is probably some data structure in the kernel | ||
58 | * than we could reused for that already. | ||
59 | * | ||
60 | * The below structure is really just good while we support one WSS per | ||
61 | * host. | ||
62 | */ | ||
63 | struct wlp_eda_node { | ||
64 | struct list_head list_node; | ||
65 | unsigned char eth_addr[ETH_ALEN]; | ||
66 | struct uwb_dev_addr dev_addr; | ||
67 | struct wlp_wss *wss; | ||
68 | unsigned char virt_addr[ETH_ALEN]; | ||
69 | u8 tag; | ||
70 | enum wlp_wss_connect state; | ||
71 | }; | ||
72 | |||
73 | typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *); | ||
74 | |||
75 | extern void wlp_eda_init(struct wlp_eda *); | ||
76 | extern void wlp_eda_release(struct wlp_eda *); | ||
77 | extern int wlp_eda_create_node(struct wlp_eda *, | ||
78 | const unsigned char eth_addr[ETH_ALEN], | ||
79 | const struct uwb_dev_addr *); | ||
80 | extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *); | ||
81 | extern int wlp_eda_update_node(struct wlp_eda *, | ||
82 | const struct uwb_dev_addr *, | ||
83 | struct wlp_wss *, | ||
84 | const unsigned char virt_addr[ETH_ALEN], | ||
85 | const u8, const enum wlp_wss_connect); | ||
86 | extern int wlp_eda_update_node_state(struct wlp_eda *, | ||
87 | const struct uwb_dev_addr *, | ||
88 | const enum wlp_wss_connect); | ||
89 | |||
90 | extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *, | ||
91 | struct wlp_eda_node *); | ||
92 | extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *); | ||
93 | extern int wlp_eda_for_virtual(struct wlp_eda *, | ||
94 | const unsigned char eth_addr[ETH_ALEN], | ||
95 | struct uwb_dev_addr *, | ||
96 | wlp_eda_for_each_f , void *); | ||
97 | |||
98 | |||
99 | extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *); | ||
100 | |||
101 | extern size_t wlp_wss_key_print(char *, size_t, u8 *); | ||
102 | |||
103 | /* Function called when no more references to WSS exists */ | ||
104 | extern void wlp_wss_release(struct kobject *); | ||
105 | |||
106 | extern void wlp_wss_reset(struct wlp_wss *); | ||
107 | extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *, | ||
108 | char *, unsigned, unsigned); | ||
109 | extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *, | ||
110 | struct uwb_dev_addr *); | ||
111 | extern ssize_t wlp_discover(struct wlp *); | ||
112 | |||
113 | extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *, | ||
114 | struct wlp_wss *, struct wlp_uuid *); | ||
115 | extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *, | ||
116 | struct uwb_dev_addr *); | ||
117 | |||
118 | struct wlp_assoc_conn_ctx { | ||
119 | struct work_struct ws; | ||
120 | struct wlp *wlp; | ||
121 | struct sk_buff *skb; | ||
122 | struct wlp_eda_node eda_entry; | ||
123 | }; | ||
124 | |||
125 | |||
126 | extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *); | ||
127 | extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *); | ||
128 | |||
129 | |||
130 | /* Message handling */ | ||
131 | struct wlp_assoc_frame_ctx { | ||
132 | struct work_struct ws; | ||
133 | struct wlp *wlp; | ||
134 | struct sk_buff *skb; | ||
135 | struct uwb_dev_addr src; | ||
136 | }; | ||
137 | |||
138 | extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *); | ||
139 | extern void wlp_handle_d1_frame(struct work_struct *); | ||
140 | extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *, | ||
141 | struct wlp_neighbor_e *); | ||
142 | extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *, | ||
143 | struct wlp_neighbor_e *, | ||
144 | struct wlp_uuid *); | ||
145 | extern void wlp_handle_c1_frame(struct work_struct *); | ||
146 | extern void wlp_handle_c3_frame(struct work_struct *); | ||
147 | extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *, | ||
148 | struct wlp_uuid *, u8 *, | ||
149 | struct uwb_mac_addr *); | ||
150 | extern int wlp_parse_f0(struct wlp *, struct sk_buff *); | ||
151 | extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *, | ||
152 | struct uwb_dev_addr *, enum wlp_assoc_type); | ||
153 | extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *, | ||
154 | u8 *, ssize_t); | ||
155 | extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *, | ||
156 | struct wlp_uuid *, ssize_t); | ||
157 | extern int __wlp_alloc_device_info(struct wlp *); | ||
158 | extern int __wlp_setup_device_info(struct wlp *); | ||
159 | |||
160 | extern struct wlp_wss_attribute wss_attribute_properties; | ||
161 | extern struct wlp_wss_attribute wss_attribute_members; | ||
162 | extern struct wlp_wss_attribute wss_attribute_state; | ||
163 | |||
164 | static inline | ||
165 | size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid) | ||
166 | { | ||
167 | size_t result; | ||
168 | |||
169 | result = scnprintf(buf, bufsize, | ||
170 | "%02x:%02x:%02x:%02x:%02x:%02x:" | ||
171 | "%02x:%02x:%02x:%02x:%02x:%02x:" | ||
172 | "%02x:%02x:%02x:%02x", | ||
173 | uuid->data[0], uuid->data[1], | ||
174 | uuid->data[2], uuid->data[3], | ||
175 | uuid->data[4], uuid->data[5], | ||
176 | uuid->data[6], uuid->data[7], | ||
177 | uuid->data[8], uuid->data[9], | ||
178 | uuid->data[10], uuid->data[11], | ||
179 | uuid->data[12], uuid->data[13], | ||
180 | uuid->data[14], uuid->data[15]); | ||
181 | return result; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * FIXME: How should a nonce be displayed? | ||
186 | */ | ||
187 | static inline | ||
188 | size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce) | ||
189 | { | ||
190 | size_t result; | ||
191 | |||
192 | result = scnprintf(buf, bufsize, | ||
193 | "%02x %02x %02x %02x %02x %02x " | ||
194 | "%02x %02x %02x %02x %02x %02x " | ||
195 | "%02x %02x %02x %02x", | ||
196 | nonce->data[0], nonce->data[1], | ||
197 | nonce->data[2], nonce->data[3], | ||
198 | nonce->data[4], nonce->data[5], | ||
199 | nonce->data[6], nonce->data[7], | ||
200 | nonce->data[8], nonce->data[9], | ||
201 | nonce->data[10], nonce->data[11], | ||
202 | nonce->data[12], nonce->data[13], | ||
203 | nonce->data[14], nonce->data[15]); | ||
204 | return result; | ||
205 | } | ||
206 | |||
207 | |||
208 | static inline | ||
209 | void wlp_session_cb(struct wlp *wlp) | ||
210 | { | ||
211 | struct completion *completion = wlp->session->cb_priv; | ||
212 | complete(completion); | ||
213 | } | ||
214 | |||
215 | static inline | ||
216 | int wlp_uuid_is_set(struct wlp_uuid *uuid) | ||
217 | { | ||
218 | struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x00, 0x00, | ||
220 | 0x00, 0x00, 0x00, 0x00, | ||
221 | 0x00, 0x00, 0x00, 0x00} }; | ||
222 | |||
223 | if (!memcmp(uuid, &zero_uuid, sizeof(*uuid))) | ||
224 | return 0; | ||
225 | return 1; | ||
226 | } | ||
227 | |||
228 | #endif /* __WLP_INTERNAL_H__ */ | ||
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c new file mode 100644 index 000000000000..0799402e73fb --- /dev/null +++ b/drivers/uwb/wlp/wlp-lc.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * FIXME: docs | ||
23 | */ | ||
24 | |||
25 | #include <linux/wlp.h> | ||
26 | #define D_LOCAL 6 | ||
27 | #include <linux/uwb/debug.h> | ||
28 | #include "wlp-internal.h" | ||
29 | |||
30 | |||
31 | static | ||
32 | void wlp_neighbor_init(struct wlp_neighbor_e *neighbor) | ||
33 | { | ||
34 | INIT_LIST_HEAD(&neighbor->wssid); | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * Create area for device information storage | ||
39 | * | ||
40 | * wlp->mutex must be held | ||
41 | */ | ||
42 | int __wlp_alloc_device_info(struct wlp *wlp) | ||
43 | { | ||
44 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
45 | BUG_ON(wlp->dev_info != NULL); | ||
46 | wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL); | ||
47 | if (wlp->dev_info == NULL) { | ||
48 | dev_err(dev, "WLP: Unable to allocate memory for " | ||
49 | "device information.\n"); | ||
50 | return -ENOMEM; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Fill in device information using function provided by driver | ||
58 | * | ||
59 | * wlp->mutex must be held | ||
60 | */ | ||
61 | static | ||
62 | void __wlp_fill_device_info(struct wlp *wlp) | ||
63 | { | ||
64 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
65 | |||
66 | BUG_ON(wlp->fill_device_info == NULL); | ||
67 | d_printf(6, dev, "Retrieving device information " | ||
68 | "from device driver.\n"); | ||
69 | wlp->fill_device_info(wlp, wlp->dev_info); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Setup device information | ||
74 | * | ||
75 | * Allocate area for device information and populate it. | ||
76 | * | ||
77 | * wlp->mutex must be held | ||
78 | */ | ||
79 | int __wlp_setup_device_info(struct wlp *wlp) | ||
80 | { | ||
81 | int result; | ||
82 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
83 | |||
84 | result = __wlp_alloc_device_info(wlp); | ||
85 | if (result < 0) { | ||
86 | dev_err(dev, "WLP: Unable to allocate area for " | ||
87 | "device information.\n"); | ||
88 | return result; | ||
89 | } | ||
90 | __wlp_fill_device_info(wlp); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Remove information about neighbor stored temporarily | ||
96 | * | ||
97 | * Information learned during discovey should only be stored when the | ||
98 | * device enrolls in the neighbor's WSS. We do need to store this | ||
99 | * information temporarily in order to present it to the user. | ||
100 | * | ||
101 | * We are only interested in keeping neighbor WSS information if that | ||
102 | * neighbor is accepting enrollment. | ||
103 | * | ||
104 | * should be called with wlp->nbmutex held | ||
105 | */ | ||
106 | void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor) | ||
107 | { | ||
108 | struct wlp_wssid_e *wssid_e, *next; | ||
109 | u8 keep; | ||
110 | if (!list_empty(&neighbor->wssid)) { | ||
111 | list_for_each_entry_safe(wssid_e, next, &neighbor->wssid, | ||
112 | node) { | ||
113 | if (wssid_e->info != NULL) { | ||
114 | keep = wssid_e->info->accept_enroll; | ||
115 | kfree(wssid_e->info); | ||
116 | wssid_e->info = NULL; | ||
117 | if (!keep) { | ||
118 | list_del(&wssid_e->node); | ||
119 | kfree(wssid_e); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | if (neighbor->info != NULL) { | ||
125 | kfree(neighbor->info); | ||
126 | neighbor->info = NULL; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Populate WLP neighborhood cache with neighbor information | ||
132 | * | ||
133 | * A new neighbor is found. If it is discoverable then we add it to the | ||
134 | * neighborhood cache. | ||
135 | * | ||
136 | */ | ||
137 | static | ||
138 | int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev) | ||
139 | { | ||
140 | int result = 0; | ||
141 | int discoverable; | ||
142 | struct wlp_neighbor_e *neighbor; | ||
143 | |||
144 | d_fnstart(6, &dev->dev, "uwb %p \n", dev); | ||
145 | d_printf(6, &dev->dev, "Found neighbor device %02x:%02x \n", | ||
146 | dev->dev_addr.data[1], dev->dev_addr.data[0]); | ||
147 | /** | ||
148 | * FIXME: | ||
149 | * Use contents of WLP IE found in beacon cache to determine if | ||
150 | * neighbor is discoverable. | ||
151 | * The device does not support WLP IE yet so this still needs to be | ||
152 | * done. Until then we assume all devices are discoverable. | ||
153 | */ | ||
154 | discoverable = 1; /* will be changed when FIXME disappears */ | ||
155 | if (discoverable) { | ||
156 | /* Add neighbor to cache for discovery */ | ||
157 | neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL); | ||
158 | if (neighbor == NULL) { | ||
159 | dev_err(&dev->dev, "Unable to create memory for " | ||
160 | "new neighbor. \n"); | ||
161 | result = -ENOMEM; | ||
162 | goto error_no_mem; | ||
163 | } | ||
164 | wlp_neighbor_init(neighbor); | ||
165 | uwb_dev_get(dev); | ||
166 | neighbor->uwb_dev = dev; | ||
167 | list_add(&neighbor->node, &wlp->neighbors); | ||
168 | } | ||
169 | error_no_mem: | ||
170 | d_fnend(6, &dev->dev, "uwb %p, result = %d \n", dev, result); | ||
171 | return result; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * Remove one neighbor from cache | ||
176 | */ | ||
177 | static | ||
178 | void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor) | ||
179 | { | ||
180 | struct wlp_wssid_e *wssid_e, *next_wssid_e; | ||
181 | |||
182 | list_for_each_entry_safe(wssid_e, next_wssid_e, | ||
183 | &neighbor->wssid, node) { | ||
184 | list_del(&wssid_e->node); | ||
185 | kfree(wssid_e); | ||
186 | } | ||
187 | uwb_dev_put(neighbor->uwb_dev); | ||
188 | list_del(&neighbor->node); | ||
189 | kfree(neighbor); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Clear entire neighborhood cache. | ||
194 | */ | ||
195 | static | ||
196 | void __wlp_neighbors_release(struct wlp *wlp) | ||
197 | { | ||
198 | struct wlp_neighbor_e *neighbor, *next; | ||
199 | if (list_empty(&wlp->neighbors)) | ||
200 | return; | ||
201 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { | ||
202 | __wlp_neighbor_release(neighbor); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | static | ||
207 | void wlp_neighbors_release(struct wlp *wlp) | ||
208 | { | ||
209 | mutex_lock(&wlp->nbmutex); | ||
210 | __wlp_neighbors_release(wlp); | ||
211 | mutex_unlock(&wlp->nbmutex); | ||
212 | } | ||
213 | |||
214 | |||
215 | |||
216 | /** | ||
217 | * Send D1 message to neighbor, receive D2 message | ||
218 | * | ||
219 | * @neighbor: neighbor to which D1 message will be sent | ||
220 | * @wss: if not NULL, it is an enrollment request for this WSS | ||
221 | * @wssid: if wss not NULL, this is the wssid of the WSS in which we | ||
222 | * want to enroll | ||
223 | * | ||
224 | * A D1/D2 exchange is done for one of two reasons: discovery or | ||
225 | * enrollment. If done for discovery the D1 message is sent to the neighbor | ||
226 | * and the contents of the D2 response is stored in a temporary cache. | ||
227 | * If done for enrollment the @wss and @wssid are provided also. In this | ||
228 | * case the D1 message is sent to the neighbor, the D2 response is parsed | ||
229 | * for enrollment of the WSS with wssid. | ||
230 | * | ||
231 | * &wss->mutex is held | ||
232 | */ | ||
233 | static | ||
234 | int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor, | ||
235 | struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
236 | { | ||
237 | int result; | ||
238 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
239 | DECLARE_COMPLETION_ONSTACK(completion); | ||
240 | struct wlp_session session; | ||
241 | struct sk_buff *skb; | ||
242 | struct wlp_frame_assoc *resp; | ||
243 | struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; | ||
244 | |||
245 | mutex_lock(&wlp->mutex); | ||
246 | if (!wlp_uuid_is_set(&wlp->uuid)) { | ||
247 | dev_err(dev, "WLP: UUID is not set. Set via sysfs to " | ||
248 | "proceed.\n"); | ||
249 | result = -ENXIO; | ||
250 | goto out; | ||
251 | } | ||
252 | /* Send D1 association frame */ | ||
253 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1); | ||
254 | if (result < 0) { | ||
255 | dev_err(dev, "Unable to send D1 frame to neighbor " | ||
256 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
257 | dev_addr->data[0], result); | ||
258 | d_printf(6, dev, "Add placeholders into buffer next to " | ||
259 | "neighbor information we have (dev address).\n"); | ||
260 | goto out; | ||
261 | } | ||
262 | /* Create session, wait for response */ | ||
263 | session.exp_message = WLP_ASSOC_D2; | ||
264 | session.cb = wlp_session_cb; | ||
265 | session.cb_priv = &completion; | ||
266 | session.neighbor_addr = *dev_addr; | ||
267 | BUG_ON(wlp->session != NULL); | ||
268 | wlp->session = &session; | ||
269 | /* Wait for D2/F0 frame */ | ||
270 | result = wait_for_completion_interruptible_timeout(&completion, | ||
271 | WLP_PER_MSG_TIMEOUT * HZ); | ||
272 | if (result == 0) { | ||
273 | result = -ETIMEDOUT; | ||
274 | dev_err(dev, "Timeout while sending D1 to neighbor " | ||
275 | "%02x:%02x.\n", dev_addr->data[1], | ||
276 | dev_addr->data[0]); | ||
277 | goto error_session; | ||
278 | } | ||
279 | if (result < 0) { | ||
280 | dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n", | ||
281 | dev_addr->data[1], dev_addr->data[0]); | ||
282 | goto error_session; | ||
283 | } | ||
284 | /* Parse message in session->data: it will be either D2 or F0 */ | ||
285 | skb = session.data; | ||
286 | resp = (void *) skb->data; | ||
287 | d_printf(6, dev, "Received response to D1 frame. \n"); | ||
288 | d_dump(6, dev, skb->data, skb->len > 72 ? 72 : skb->len); | ||
289 | |||
290 | if (resp->type == WLP_ASSOC_F0) { | ||
291 | result = wlp_parse_f0(wlp, skb); | ||
292 | if (result < 0) | ||
293 | dev_err(dev, "WLP: Unable to parse F0 from neighbor " | ||
294 | "%02x:%02x.\n", dev_addr->data[1], | ||
295 | dev_addr->data[0]); | ||
296 | result = -EINVAL; | ||
297 | goto error_resp_parse; | ||
298 | } | ||
299 | if (wss == NULL) { | ||
300 | /* Discovery */ | ||
301 | result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor); | ||
302 | if (result < 0) { | ||
303 | dev_err(dev, "WLP: Unable to parse D2 message from " | ||
304 | "neighbor %02x:%02x for discovery.\n", | ||
305 | dev_addr->data[1], dev_addr->data[0]); | ||
306 | goto error_resp_parse; | ||
307 | } | ||
308 | } else { | ||
309 | /* Enrollment */ | ||
310 | result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor, | ||
311 | wssid); | ||
312 | if (result < 0) { | ||
313 | dev_err(dev, "WLP: Unable to parse D2 message from " | ||
314 | "neighbor %02x:%02x for enrollment.\n", | ||
315 | dev_addr->data[1], dev_addr->data[0]); | ||
316 | goto error_resp_parse; | ||
317 | } | ||
318 | } | ||
319 | error_resp_parse: | ||
320 | kfree_skb(skb); | ||
321 | error_session: | ||
322 | wlp->session = NULL; | ||
323 | out: | ||
324 | mutex_unlock(&wlp->mutex); | ||
325 | return result; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * Enroll into WSS of provided WSSID by using neighbor as registrar | ||
330 | * | ||
331 | * &wss->mutex is held | ||
332 | */ | ||
333 | int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor, | ||
334 | struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
335 | { | ||
336 | int result = 0; | ||
337 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
338 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
339 | struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; | ||
340 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
341 | d_fnstart(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n", | ||
342 | wlp, neighbor, wss, wssid, buf); | ||
343 | d_printf(6, dev, "Complete me.\n"); | ||
344 | result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid); | ||
345 | if (result < 0) { | ||
346 | dev_err(dev, "WLP: D1/D2 message exchange for enrollment " | ||
347 | "failed. result = %d \n", result); | ||
348 | goto out; | ||
349 | } | ||
350 | if (wss->state != WLP_WSS_STATE_PART_ENROLLED) { | ||
351 | dev_err(dev, "WLP: Unable to enroll into WSS %s using " | ||
352 | "neighbor %02x:%02x. \n", buf, | ||
353 | dev_addr->data[1], dev_addr->data[0]); | ||
354 | result = -EINVAL; | ||
355 | goto out; | ||
356 | } | ||
357 | if (wss->secure_status == WLP_WSS_SECURE) { | ||
358 | dev_err(dev, "FIXME: need to complete secure enrollment.\n"); | ||
359 | result = -EINVAL; | ||
360 | goto error; | ||
361 | } else { | ||
362 | wss->state = WLP_WSS_STATE_ENROLLED; | ||
363 | d_printf(2, dev, "WLP: Success Enrollment into unsecure WSS " | ||
364 | "%s using neighbor %02x:%02x. \n", buf, | ||
365 | dev_addr->data[1], dev_addr->data[0]); | ||
366 | } | ||
367 | |||
368 | d_fnend(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n", | ||
369 | wlp, neighbor, wss, wssid, buf); | ||
370 | out: | ||
371 | return result; | ||
372 | error: | ||
373 | wlp_wss_reset(wss); | ||
374 | return result; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * Discover WSS information of neighbor's active WSS | ||
379 | */ | ||
380 | static | ||
381 | int wlp_discover_neighbor(struct wlp *wlp, | ||
382 | struct wlp_neighbor_e *neighbor) | ||
383 | { | ||
384 | return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL); | ||
385 | } | ||
386 | |||
387 | |||
388 | /** | ||
389 | * Each neighbor in the neighborhood cache is discoverable. Discover it. | ||
390 | * | ||
391 | * Discovery is done through sending of D1 association frame and parsing | ||
392 | * the D2 association frame response. Only wssid from D2 will be included | ||
393 | * in neighbor cache, rest is just displayed to user and forgotten. | ||
394 | * | ||
395 | * The discovery is not done in parallel. This is simple and enables us to | ||
396 | * maintain only one association context. | ||
397 | * | ||
398 | * The discovery of one neighbor does not affect the other, but if the | ||
399 | * discovery of a neighbor fails it is removed from the neighborhood cache. | ||
400 | */ | ||
401 | static | ||
402 | int wlp_discover_all_neighbors(struct wlp *wlp) | ||
403 | { | ||
404 | int result = 0; | ||
405 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
406 | struct wlp_neighbor_e *neighbor, *next; | ||
407 | |||
408 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { | ||
409 | result = wlp_discover_neighbor(wlp, neighbor); | ||
410 | if (result < 0) { | ||
411 | dev_err(dev, "WLP: Unable to discover neighbor " | ||
412 | "%02x:%02x, removing from neighborhood. \n", | ||
413 | neighbor->uwb_dev->dev_addr.data[1], | ||
414 | neighbor->uwb_dev->dev_addr.data[0]); | ||
415 | __wlp_neighbor_release(neighbor); | ||
416 | } | ||
417 | } | ||
418 | return result; | ||
419 | } | ||
420 | |||
421 | static int wlp_add_neighbor_helper(struct device *dev, void *priv) | ||
422 | { | ||
423 | struct wlp *wlp = priv; | ||
424 | struct uwb_dev *uwb_dev = to_uwb_dev(dev); | ||
425 | |||
426 | return wlp_add_neighbor(wlp, uwb_dev); | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * Discover WLP neighborhood | ||
431 | * | ||
432 | * Will send D1 association frame to all devices in beacon group that have | ||
433 | * discoverable bit set in WLP IE. D2 frames will be received, information | ||
434 | * displayed to user in @buf. Partial information (from D2 association | ||
435 | * frame) will be cached to assist with future association | ||
436 | * requests. | ||
437 | * | ||
438 | * The discovery of the WLP neighborhood is triggered by the user. This | ||
439 | * should occur infrequently and we thus free current cache and re-allocate | ||
440 | * memory if needed. | ||
441 | * | ||
442 | * If one neighbor fails during initial discovery (determining if it is a | ||
443 | * neighbor or not), we fail all - note that interaction with neighbor has | ||
444 | * not occured at this point so if a failure occurs we know something went wrong | ||
445 | * locally. We thus undo everything. | ||
446 | */ | ||
447 | ssize_t wlp_discover(struct wlp *wlp) | ||
448 | { | ||
449 | int result = 0; | ||
450 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
451 | |||
452 | d_fnstart(6, dev, "wlp %p \n", wlp); | ||
453 | mutex_lock(&wlp->nbmutex); | ||
454 | /* Clear current neighborhood cache. */ | ||
455 | __wlp_neighbors_release(wlp); | ||
456 | /* Determine which devices in neighborhood. Repopulate cache. */ | ||
457 | result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp); | ||
458 | if (result < 0) { | ||
459 | /* May have partial neighbor information, release all. */ | ||
460 | __wlp_neighbors_release(wlp); | ||
461 | goto error_dev_for_each; | ||
462 | } | ||
463 | /* Discover the properties of devices in neighborhood. */ | ||
464 | result = wlp_discover_all_neighbors(wlp); | ||
465 | /* In case of failure we still print our partial results. */ | ||
466 | if (result < 0) { | ||
467 | dev_err(dev, "Unable to fully discover neighborhood. \n"); | ||
468 | result = 0; | ||
469 | } | ||
470 | error_dev_for_each: | ||
471 | mutex_unlock(&wlp->nbmutex); | ||
472 | d_fnend(6, dev, "wlp %p \n", wlp); | ||
473 | return result; | ||
474 | } | ||
475 | |||
476 | /** | ||
477 | * Handle events from UWB stack | ||
478 | * | ||
479 | * We handle events conservatively. If a neighbor goes off the air we | ||
480 | * remove it from the neighborhood. If an association process is in | ||
481 | * progress this function will block waiting for the nbmutex to become | ||
482 | * free. The association process will thus be allowed to complete before it | ||
483 | * is removed. | ||
484 | */ | ||
485 | static | ||
486 | void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, | ||
487 | enum uwb_notifs event) | ||
488 | { | ||
489 | struct wlp *wlp = _wlp; | ||
490 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
491 | struct wlp_neighbor_e *neighbor, *next; | ||
492 | int result; | ||
493 | switch (event) { | ||
494 | case UWB_NOTIF_ONAIR: | ||
495 | d_printf(6, dev, "UWB device %02x:%02x is onair\n", | ||
496 | uwb_dev->dev_addr.data[1], | ||
497 | uwb_dev->dev_addr.data[0]); | ||
498 | result = wlp_eda_create_node(&wlp->eda, | ||
499 | uwb_dev->mac_addr.data, | ||
500 | &uwb_dev->dev_addr); | ||
501 | if (result < 0) | ||
502 | dev_err(dev, "WLP: Unable to add new neighbor " | ||
503 | "%02x:%02x to EDA cache.\n", | ||
504 | uwb_dev->dev_addr.data[1], | ||
505 | uwb_dev->dev_addr.data[0]); | ||
506 | break; | ||
507 | case UWB_NOTIF_OFFAIR: | ||
508 | d_printf(6, dev, "UWB device %02x:%02x is offair\n", | ||
509 | uwb_dev->dev_addr.data[1], | ||
510 | uwb_dev->dev_addr.data[0]); | ||
511 | wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr); | ||
512 | mutex_lock(&wlp->nbmutex); | ||
513 | list_for_each_entry_safe(neighbor, next, &wlp->neighbors, | ||
514 | node) { | ||
515 | if (neighbor->uwb_dev == uwb_dev) { | ||
516 | d_printf(6, dev, "Removing device from " | ||
517 | "neighborhood.\n"); | ||
518 | __wlp_neighbor_release(neighbor); | ||
519 | } | ||
520 | } | ||
521 | mutex_unlock(&wlp->nbmutex); | ||
522 | break; | ||
523 | default: | ||
524 | dev_err(dev, "don't know how to handle event %d from uwb\n", | ||
525 | event); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | int wlp_setup(struct wlp *wlp, struct uwb_rc *rc) | ||
530 | { | ||
531 | struct device *dev = &rc->uwb_dev.dev; | ||
532 | int result; | ||
533 | |||
534 | d_fnstart(6, dev, "wlp %p\n", wlp); | ||
535 | BUG_ON(wlp->fill_device_info == NULL); | ||
536 | BUG_ON(wlp->xmit_frame == NULL); | ||
537 | BUG_ON(wlp->stop_queue == NULL); | ||
538 | BUG_ON(wlp->start_queue == NULL); | ||
539 | wlp->rc = rc; | ||
540 | wlp_eda_init(&wlp->eda);/* Set up address cache */ | ||
541 | wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb; | ||
542 | wlp->uwb_notifs_handler.data = wlp; | ||
543 | uwb_notifs_register(rc, &wlp->uwb_notifs_handler); | ||
544 | |||
545 | uwb_pal_init(&wlp->pal); | ||
546 | result = uwb_pal_register(rc, &wlp->pal); | ||
547 | if (result < 0) | ||
548 | uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); | ||
549 | |||
550 | d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result); | ||
551 | return result; | ||
552 | } | ||
553 | EXPORT_SYMBOL_GPL(wlp_setup); | ||
554 | |||
555 | void wlp_remove(struct wlp *wlp) | ||
556 | { | ||
557 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
558 | d_fnstart(6, dev, "wlp %p\n", wlp); | ||
559 | wlp_neighbors_release(wlp); | ||
560 | uwb_pal_unregister(wlp->rc, &wlp->pal); | ||
561 | uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); | ||
562 | wlp_eda_release(&wlp->eda); | ||
563 | mutex_lock(&wlp->mutex); | ||
564 | if (wlp->dev_info != NULL) | ||
565 | kfree(wlp->dev_info); | ||
566 | mutex_unlock(&wlp->mutex); | ||
567 | wlp->rc = NULL; | ||
568 | /* We have to use NULL here because this function can be called | ||
569 | * when the device disappeared. */ | ||
570 | d_fnend(6, NULL, "wlp %p\n", wlp); | ||
571 | } | ||
572 | EXPORT_SYMBOL_GPL(wlp_remove); | ||
573 | |||
574 | /** | ||
575 | * wlp_reset_all - reset the WLP hardware | ||
576 | * @wlp: the WLP device to reset. | ||
577 | * | ||
578 | * This schedules a full hardware reset of the WLP device. The radio | ||
579 | * controller and any other PALs will also be reset. | ||
580 | */ | ||
581 | void wlp_reset_all(struct wlp *wlp) | ||
582 | { | ||
583 | uwb_rc_reset_all(wlp->rc); | ||
584 | } | ||
585 | EXPORT_SYMBOL_GPL(wlp_reset_all); | ||
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c new file mode 100644 index 000000000000..96b18c9bd6e9 --- /dev/null +++ b/drivers/uwb/wlp/wss-lc.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2007 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Implementation of the WLP association protocol. | ||
23 | * | ||
24 | * FIXME: Docs | ||
25 | * | ||
26 | * A UWB network interface will configure a WSS through wlp_wss_setup() after | ||
27 | * the interface has been assigned a MAC address, typically after | ||
28 | * "ifconfig" has been called. When the interface goes down it should call | ||
29 | * wlp_wss_remove(). | ||
30 | * | ||
31 | * When the WSS is ready for use the user interacts via sysfs to create, | ||
32 | * discover, and activate WSS. | ||
33 | * | ||
34 | * wlp_wss_enroll_activate() | ||
35 | * | ||
36 | * wlp_wss_create_activate() | ||
37 | * wlp_wss_set_wssid_hash() | ||
38 | * wlp_wss_comp_wssid_hash() | ||
39 | * wlp_wss_sel_bcast_addr() | ||
40 | * wlp_wss_sysfs_add() | ||
41 | * | ||
42 | * Called when no more references to WSS exist: | ||
43 | * wlp_wss_release() | ||
44 | * wlp_wss_reset() | ||
45 | */ | ||
46 | |||
47 | #include <linux/etherdevice.h> /* for is_valid_ether_addr */ | ||
48 | #include <linux/skbuff.h> | ||
49 | #include <linux/wlp.h> | ||
50 | #define D_LOCAL 5 | ||
51 | #include <linux/uwb/debug.h> | ||
52 | #include "wlp-internal.h" | ||
53 | |||
54 | |||
55 | size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key) | ||
56 | { | ||
57 | size_t result; | ||
58 | |||
59 | result = scnprintf(buf, bufsize, | ||
60 | "%02x %02x %02x %02x %02x %02x " | ||
61 | "%02x %02x %02x %02x %02x %02x " | ||
62 | "%02x %02x %02x %02x", | ||
63 | key[0], key[1], key[2], key[3], | ||
64 | key[4], key[5], key[6], key[7], | ||
65 | key[8], key[9], key[10], key[11], | ||
66 | key[12], key[13], key[14], key[15]); | ||
67 | return result; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * Compute WSSID hash | ||
72 | * WLP Draft 0.99 [7.2.1] | ||
73 | * | ||
74 | * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR | ||
75 | * of all octets in the WSSID. | ||
76 | */ | ||
77 | static | ||
78 | u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid) | ||
79 | { | ||
80 | return wssid->data[0] ^ wssid->data[1] ^ wssid->data[2] | ||
81 | ^ wssid->data[3] ^ wssid->data[4] ^ wssid->data[5] | ||
82 | ^ wssid->data[6] ^ wssid->data[7] ^ wssid->data[8] | ||
83 | ^ wssid->data[9] ^ wssid->data[10] ^ wssid->data[11] | ||
84 | ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14] | ||
85 | ^ wssid->data[15]; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * Select a multicast EUI-48 for the WSS broadcast address. | ||
90 | * WLP Draft 0.99 [7.2.1] | ||
91 | * | ||
92 | * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP | ||
93 | * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive. | ||
94 | * | ||
95 | * This address is currently hardcoded. | ||
96 | * FIXME? | ||
97 | */ | ||
98 | static | ||
99 | struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss) | ||
100 | { | ||
101 | struct uwb_mac_addr bcast = { | ||
102 | .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 } | ||
103 | }; | ||
104 | return bcast; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Clear the contents of the WSS structure - all except kobj, mutex, virtual | ||
109 | * | ||
110 | * We do not want to reinitialize - the internal kobj should not change as | ||
111 | * it still points to the parent received during setup. The mutex should | ||
112 | * remain also. We thus just reset values individually. | ||
113 | * The virutal address assigned to WSS will remain the same for the | ||
114 | * lifetime of the WSS. We only reset the fields that can change during its | ||
115 | * lifetime. | ||
116 | */ | ||
117 | void wlp_wss_reset(struct wlp_wss *wss) | ||
118 | { | ||
119 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
120 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
121 | d_fnstart(5, dev, "wss (%p) \n", wss); | ||
122 | memset(&wss->wssid, 0, sizeof(wss->wssid)); | ||
123 | wss->hash = 0; | ||
124 | memset(&wss->name[0], 0, sizeof(wss->name)); | ||
125 | memset(&wss->bcast, 0, sizeof(wss->bcast)); | ||
126 | wss->secure_status = WLP_WSS_UNSECURE; | ||
127 | memset(&wss->master_key[0], 0, sizeof(wss->master_key)); | ||
128 | wss->tag = 0; | ||
129 | wss->state = WLP_WSS_STATE_NONE; | ||
130 | d_fnend(5, dev, "wss (%p) \n", wss); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * Create sysfs infrastructure for WSS | ||
135 | * | ||
136 | * The WSS is configured to have the interface as parent (see wlp_wss_setup()) | ||
137 | * a new sysfs directory that includes wssid as its name is created in the | ||
138 | * interface's sysfs directory. The group of files interacting with WSS are | ||
139 | * created also. | ||
140 | */ | ||
141 | static | ||
142 | int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str) | ||
143 | { | ||
144 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
145 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
146 | int result; | ||
147 | |||
148 | d_fnstart(5, dev, "wss (%p), wssid: %s\n", wss, wssid_str); | ||
149 | result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str); | ||
150 | if (result < 0) | ||
151 | return result; | ||
152 | wss->kobj.ktype = &wss_ktype; | ||
153 | result = kobject_init_and_add(&wss->kobj, | ||
154 | &wss_ktype, wss->kobj.parent, "wlp"); | ||
155 | if (result < 0) { | ||
156 | dev_err(dev, "WLP: Cannot register WSS kobject.\n"); | ||
157 | goto error_kobject_register; | ||
158 | } | ||
159 | result = sysfs_create_group(&wss->kobj, &wss_attr_group); | ||
160 | if (result < 0) { | ||
161 | dev_err(dev, "WLP: Cannot register WSS attributes: %d\n", | ||
162 | result); | ||
163 | goto error_sysfs_create_group; | ||
164 | } | ||
165 | d_fnend(5, dev, "Completed. result = %d \n", result); | ||
166 | return 0; | ||
167 | error_sysfs_create_group: | ||
168 | |||
169 | kobject_put(&wss->kobj); /* will free name if needed */ | ||
170 | return result; | ||
171 | error_kobject_register: | ||
172 | kfree(wss->kobj.name); | ||
173 | wss->kobj.name = NULL; | ||
174 | wss->kobj.ktype = NULL; | ||
175 | return result; | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Release WSS | ||
181 | * | ||
182 | * No more references exist to this WSS. We should undo everything that was | ||
183 | * done in wlp_wss_create_activate() except removing the group. The group | ||
184 | * is not removed because an object can be unregistered before the group is | ||
185 | * created. We also undo any additional operations on the WSS after this | ||
186 | * (addition of members). | ||
187 | * | ||
188 | * If memory was allocated for the kobject's name then it will | ||
189 | * be freed by the kobject system during this time. | ||
190 | * | ||
191 | * The EDA cache is removed and reinitilized when the WSS is removed. We | ||
192 | * thus loose knowledge of members of this WSS at that time and need not do | ||
193 | * it here. | ||
194 | */ | ||
195 | void wlp_wss_release(struct kobject *kobj) | ||
196 | { | ||
197 | struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj); | ||
198 | |||
199 | wlp_wss_reset(wss); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Enroll into a WSS using provided neighbor as registrar | ||
204 | * | ||
205 | * First search the neighborhood information to learn which neighbor is | ||
206 | * referred to, next proceed with enrollment. | ||
207 | * | ||
208 | * &wss->mutex is held | ||
209 | */ | ||
210 | static | ||
211 | int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
212 | struct uwb_dev_addr *dest) | ||
213 | { | ||
214 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
215 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
216 | struct wlp_neighbor_e *neighbor; | ||
217 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
218 | int result = -ENXIO; | ||
219 | struct uwb_dev_addr *dev_addr; | ||
220 | |||
221 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
222 | d_fnstart(5, dev, "wss %p, wssid %s, registrar %02x:%02x \n", | ||
223 | wss, buf, dest->data[1], dest->data[0]); | ||
224 | mutex_lock(&wlp->nbmutex); | ||
225 | list_for_each_entry(neighbor, &wlp->neighbors, node) { | ||
226 | dev_addr = &neighbor->uwb_dev->dev_addr; | ||
227 | if (!memcmp(dest, dev_addr, sizeof(*dest))) { | ||
228 | d_printf(5, dev, "Neighbor %02x:%02x is valid, " | ||
229 | "enrolling. \n", | ||
230 | dev_addr->data[1], dev_addr->data[0]); | ||
231 | result = wlp_enroll_neighbor(wlp, neighbor, wss, | ||
232 | wssid); | ||
233 | break; | ||
234 | } | ||
235 | } | ||
236 | if (result == -ENXIO) | ||
237 | dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n", | ||
238 | dest->data[1], dest->data[0]); | ||
239 | mutex_unlock(&wlp->nbmutex); | ||
240 | d_fnend(5, dev, "wss %p, wssid %s, registrar %02x:%02x, result %d \n", | ||
241 | wss, buf, dest->data[1], dest->data[0], result); | ||
242 | return result; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * Enroll into a WSS previously discovered | ||
247 | * | ||
248 | * User provides WSSID of WSS, search for neighbor that has this WSS | ||
249 | * activated and attempt to enroll. | ||
250 | * | ||
251 | * &wss->mutex is held | ||
252 | */ | ||
253 | static | ||
254 | int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid) | ||
255 | { | ||
256 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
257 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
258 | struct wlp_neighbor_e *neighbor; | ||
259 | struct wlp_wssid_e *wssid_e; | ||
260 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
261 | int result = -ENXIO; | ||
262 | |||
263 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
264 | d_fnstart(5, dev, "wss %p, wssid %s \n", wss, buf); | ||
265 | mutex_lock(&wlp->nbmutex); | ||
266 | list_for_each_entry(neighbor, &wlp->neighbors, node) { | ||
267 | list_for_each_entry(wssid_e, &neighbor->wssid, node) { | ||
268 | if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) { | ||
269 | d_printf(5, dev, "Found WSSID %s in neighbor " | ||
270 | "%02x:%02x cache. \n", buf, | ||
271 | neighbor->uwb_dev->dev_addr.data[1], | ||
272 | neighbor->uwb_dev->dev_addr.data[0]); | ||
273 | result = wlp_enroll_neighbor(wlp, neighbor, | ||
274 | wss, wssid); | ||
275 | if (result == 0) /* enrollment success */ | ||
276 | goto out; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | out: | ||
282 | if (result == -ENXIO) | ||
283 | dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf); | ||
284 | mutex_unlock(&wlp->nbmutex); | ||
285 | d_fnend(5, dev, "wss %p, wssid %s, result %d \n", wss, buf, result); | ||
286 | return result; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * Enroll into WSS with provided WSSID, registrar may be provided | ||
291 | * | ||
292 | * @wss: out WSS that will be enrolled | ||
293 | * @wssid: wssid of neighboring WSS that we want to enroll in | ||
294 | * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any | ||
295 | * neighbor can be used as registrar. | ||
296 | * | ||
297 | * &wss->mutex is held | ||
298 | */ | ||
299 | static | ||
300 | int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
301 | struct uwb_dev_addr *devaddr) | ||
302 | { | ||
303 | int result; | ||
304 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
305 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
306 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
307 | struct uwb_dev_addr bcast = {.data = {0xff, 0xff} }; | ||
308 | |||
309 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
310 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
311 | dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf); | ||
312 | result = -EEXIST; | ||
313 | goto error; | ||
314 | } | ||
315 | if (!memcmp(&bcast, devaddr, sizeof(bcast))) { | ||
316 | d_printf(5, dev, "Request to enroll in discovered WSS " | ||
317 | "with WSSID %s \n", buf); | ||
318 | result = wlp_wss_enroll_discovered(wss, wssid); | ||
319 | } else { | ||
320 | d_printf(5, dev, "Request to enroll in WSSID %s with " | ||
321 | "registrar %02x:%02x\n", buf, devaddr->data[1], | ||
322 | devaddr->data[0]); | ||
323 | result = wlp_wss_enroll_target(wss, wssid, devaddr); | ||
324 | } | ||
325 | if (result < 0) { | ||
326 | dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n", | ||
327 | buf, result); | ||
328 | goto error; | ||
329 | } | ||
330 | d_printf(2, dev, "Successfully enrolled into WSS %s \n", buf); | ||
331 | result = wlp_wss_sysfs_add(wss, buf); | ||
332 | if (result < 0) { | ||
333 | dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n"); | ||
334 | wlp_wss_reset(wss); | ||
335 | } | ||
336 | error: | ||
337 | return result; | ||
338 | |||
339 | } | ||
340 | |||
341 | /** | ||
342 | * Activate given WSS | ||
343 | * | ||
344 | * Prior to activation a WSS must be enrolled. To activate a WSS a device | ||
345 | * includes the WSS hash in the WLP IE in its beacon in each superframe. | ||
346 | * WLP 0.99 [7.2.5]. | ||
347 | * | ||
348 | * The WSS tag is also computed at this time. We only support one activated | ||
349 | * WSS so we can use the hash as a tag - there will never be a conflict. | ||
350 | * | ||
351 | * We currently only support one activated WSS so only one WSS hash is | ||
352 | * included in the WLP IE. | ||
353 | */ | ||
354 | static | ||
355 | int wlp_wss_activate(struct wlp_wss *wss) | ||
356 | { | ||
357 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
358 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
359 | struct uwb_rc *uwb_rc = wlp->rc; | ||
360 | int result; | ||
361 | struct { | ||
362 | struct wlp_ie wlp_ie; | ||
363 | u8 hash; /* only include one hash */ | ||
364 | } ie_data; | ||
365 | |||
366 | d_fnstart(5, dev, "Activating WSS %p. \n", wss); | ||
367 | BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED); | ||
368 | wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid); | ||
369 | wss->tag = wss->hash; | ||
370 | memset(&ie_data, 0, sizeof(ie_data)); | ||
371 | ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP; | ||
372 | ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr); | ||
373 | wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash)); | ||
374 | ie_data.hash = wss->hash; | ||
375 | result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr, | ||
376 | sizeof(ie_data)); | ||
377 | if (result < 0) { | ||
378 | dev_err(dev, "WLP: Unable to add WLP IE to beacon. " | ||
379 | "result = %d.\n", result); | ||
380 | goto error_wlp_ie; | ||
381 | } | ||
382 | wss->state = WLP_WSS_STATE_ACTIVE; | ||
383 | result = 0; | ||
384 | error_wlp_ie: | ||
385 | d_fnend(5, dev, "Activating WSS %p, result = %d \n", wss, result); | ||
386 | return result; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * Enroll in and activate WSS identified by provided WSSID | ||
391 | * | ||
392 | * The neighborhood cache should contain a list of all neighbors and the | ||
393 | * WSS they have activated. Based on that cache we search which neighbor we | ||
394 | * can perform the association process with. The user also has option to | ||
395 | * specify which neighbor it prefers as registrar. | ||
396 | * Successful enrollment is followed by activation. | ||
397 | * Successful activation will create the sysfs directory containing | ||
398 | * specific information regarding this WSS. | ||
399 | */ | ||
400 | int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
401 | struct uwb_dev_addr *devaddr) | ||
402 | { | ||
403 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
404 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
405 | int result = 0; | ||
406 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
407 | |||
408 | d_fnstart(5, dev, "Enrollment and activation requested. \n"); | ||
409 | mutex_lock(&wss->mutex); | ||
410 | result = wlp_wss_enroll(wss, wssid, devaddr); | ||
411 | if (result < 0) { | ||
412 | wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); | ||
413 | dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf); | ||
414 | goto error_enroll; | ||
415 | } | ||
416 | result = wlp_wss_activate(wss); | ||
417 | if (result < 0) { | ||
418 | dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment " | ||
419 | "result = %d \n", result); | ||
420 | /* Undo enrollment */ | ||
421 | wlp_wss_reset(wss); | ||
422 | goto error_activate; | ||
423 | } | ||
424 | error_activate: | ||
425 | error_enroll: | ||
426 | mutex_unlock(&wss->mutex); | ||
427 | d_fnend(5, dev, "Completed. result = %d \n", result); | ||
428 | return result; | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * Create, enroll, and activate a new WSS | ||
433 | * | ||
434 | * @wssid: new wssid provided by user | ||
435 | * @name: WSS name requested by used. | ||
436 | * @sec_status: security status requested by user | ||
437 | * | ||
438 | * A user requested the creation of a new WSS. All operations are done | ||
439 | * locally. The new WSS will be stored locally, the hash will be included | ||
440 | * in the WLP IE, and the sysfs infrastructure for this WSS will be | ||
441 | * created. | ||
442 | */ | ||
443 | int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid, | ||
444 | char *name, unsigned sec_status, unsigned accept) | ||
445 | { | ||
446 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
447 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
448 | int result = 0; | ||
449 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
450 | d_fnstart(5, dev, "Request to create new WSS.\n"); | ||
451 | result = wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
452 | d_printf(5, dev, "Request to create WSS: WSSID=%s, name=%s, " | ||
453 | "sec_status=%u, accepting enrollment=%u \n", | ||
454 | buf, name, sec_status, accept); | ||
455 | if (!mutex_trylock(&wss->mutex)) { | ||
456 | dev_err(dev, "WLP: WLP association session in progress.\n"); | ||
457 | return -EBUSY; | ||
458 | } | ||
459 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
460 | dev_err(dev, "WLP: WSS already exists. Not creating new.\n"); | ||
461 | result = -EEXIST; | ||
462 | goto out; | ||
463 | } | ||
464 | if (wss->kobj.parent == NULL) { | ||
465 | dev_err(dev, "WLP: WSS parent not ready. Is network interface " | ||
466 | "up?\n"); | ||
467 | result = -ENXIO; | ||
468 | goto out; | ||
469 | } | ||
470 | if (sec_status == WLP_WSS_SECURE) { | ||
471 | dev_err(dev, "WLP: FIXME Creation of secure WSS not " | ||
472 | "supported yet.\n"); | ||
473 | result = -EINVAL; | ||
474 | goto out; | ||
475 | } | ||
476 | wss->wssid = *wssid; | ||
477 | memcpy(wss->name, name, sizeof(wss->name)); | ||
478 | wss->bcast = wlp_wss_sel_bcast_addr(wss); | ||
479 | wss->secure_status = sec_status; | ||
480 | wss->accept_enroll = accept; | ||
481 | /*wss->virtual_addr is initialized in call to wlp_wss_setup*/ | ||
482 | /* sysfs infrastructure */ | ||
483 | result = wlp_wss_sysfs_add(wss, buf); | ||
484 | if (result < 0) { | ||
485 | dev_err(dev, "Cannot set up sysfs for WSS kobject.\n"); | ||
486 | wlp_wss_reset(wss); | ||
487 | goto out; | ||
488 | } else | ||
489 | result = 0; | ||
490 | wss->state = WLP_WSS_STATE_ENROLLED; | ||
491 | result = wlp_wss_activate(wss); | ||
492 | if (result < 0) { | ||
493 | dev_err(dev, "WLP: Unable to activate WSS. Undoing " | ||
494 | "enrollment\n"); | ||
495 | wlp_wss_reset(wss); | ||
496 | goto out; | ||
497 | } | ||
498 | result = 0; | ||
499 | out: | ||
500 | mutex_unlock(&wss->mutex); | ||
501 | d_fnend(5, dev, "Completed. result = %d \n", result); | ||
502 | return result; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * Determine if neighbor has WSS activated | ||
507 | * | ||
508 | * @returns: 1 if neighbor has WSS activated, zero otherwise | ||
509 | * | ||
510 | * This can be done in two ways: | ||
511 | * - send a C1 frame, parse C2/F0 response | ||
512 | * - examine the WLP IE sent by the neighbor | ||
513 | * | ||
514 | * The WLP IE is not fully supported in hardware so we use the C1/C2 frame | ||
515 | * exchange to determine if a WSS is activated. Using the WLP IE should be | ||
516 | * faster and should be used when it becomes possible. | ||
517 | */ | ||
518 | int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss, | ||
519 | struct uwb_dev_addr *dev_addr) | ||
520 | { | ||
521 | int result = 0; | ||
522 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
523 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
524 | DECLARE_COMPLETION_ONSTACK(completion); | ||
525 | struct wlp_session session; | ||
526 | struct sk_buff *skb; | ||
527 | struct wlp_frame_assoc *resp; | ||
528 | struct wlp_uuid wssid; | ||
529 | |||
530 | wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); | ||
531 | d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", | ||
532 | wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); | ||
533 | mutex_lock(&wlp->mutex); | ||
534 | /* Send C1 association frame */ | ||
535 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1); | ||
536 | if (result < 0) { | ||
537 | dev_err(dev, "Unable to send C1 frame to neighbor " | ||
538 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
539 | dev_addr->data[0], result); | ||
540 | result = 0; | ||
541 | goto out; | ||
542 | } | ||
543 | /* Create session, wait for response */ | ||
544 | session.exp_message = WLP_ASSOC_C2; | ||
545 | session.cb = wlp_session_cb; | ||
546 | session.cb_priv = &completion; | ||
547 | session.neighbor_addr = *dev_addr; | ||
548 | BUG_ON(wlp->session != NULL); | ||
549 | wlp->session = &session; | ||
550 | /* Wait for C2/F0 frame */ | ||
551 | result = wait_for_completion_interruptible_timeout(&completion, | ||
552 | WLP_PER_MSG_TIMEOUT * HZ); | ||
553 | if (result == 0) { | ||
554 | dev_err(dev, "Timeout while sending C1 to neighbor " | ||
555 | "%02x:%02x.\n", dev_addr->data[1], | ||
556 | dev_addr->data[0]); | ||
557 | goto out; | ||
558 | } | ||
559 | if (result < 0) { | ||
560 | dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n", | ||
561 | dev_addr->data[1], dev_addr->data[0]); | ||
562 | result = 0; | ||
563 | goto out; | ||
564 | } | ||
565 | /* Parse message in session->data: it will be either C2 or F0 */ | ||
566 | skb = session.data; | ||
567 | resp = (void *) skb->data; | ||
568 | d_printf(5, dev, "Received response to C1 frame. \n"); | ||
569 | d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len); | ||
570 | if (resp->type == WLP_ASSOC_F0) { | ||
571 | result = wlp_parse_f0(wlp, skb); | ||
572 | if (result < 0) | ||
573 | dev_err(dev, "WLP: unable to parse incoming F0 " | ||
574 | "frame from neighbor %02x:%02x.\n", | ||
575 | dev_addr->data[1], dev_addr->data[0]); | ||
576 | result = 0; | ||
577 | goto error_resp_parse; | ||
578 | } | ||
579 | /* WLP version and message type fields have already been parsed */ | ||
580 | result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid, | ||
581 | skb->len - sizeof(*resp)); | ||
582 | if (result < 0) { | ||
583 | dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n"); | ||
584 | result = 0; | ||
585 | goto error_resp_parse; | ||
586 | } | ||
587 | if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) { | ||
588 | d_printf(5, dev, "WSSID in C2 frame matches local " | ||
589 | "active WSS.\n"); | ||
590 | result = 1; | ||
591 | } else { | ||
592 | dev_err(dev, "WLP: Received a C2 frame without matching " | ||
593 | "WSSID.\n"); | ||
594 | result = 0; | ||
595 | } | ||
596 | error_resp_parse: | ||
597 | kfree_skb(skb); | ||
598 | out: | ||
599 | wlp->session = NULL; | ||
600 | mutex_unlock(&wlp->mutex); | ||
601 | d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", | ||
602 | wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); | ||
603 | return result; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Activate connection with neighbor by updating EDA cache | ||
608 | * | ||
609 | * @wss: local WSS to which neighbor wants to connect | ||
610 | * @dev_addr: neighbor's address | ||
611 | * @wssid: neighbor's WSSID - must be same as our WSS's WSSID | ||
612 | * @tag: neighbor's WSS tag used to identify frames transmitted by it | ||
613 | * @virt_addr: neighbor's virtual EUI-48 | ||
614 | */ | ||
615 | static | ||
616 | int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss, | ||
617 | struct uwb_dev_addr *dev_addr, | ||
618 | struct wlp_uuid *wssid, u8 *tag, | ||
619 | struct uwb_mac_addr *virt_addr) | ||
620 | { | ||
621 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
622 | int result = 0; | ||
623 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
624 | wlp_wss_uuid_print(buf, sizeof(buf), wssid); | ||
625 | d_fnstart(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual " | ||
626 | "%02x:%02x:%02x:%02x:%02x:%02x \n", wlp, wss, buf, *tag, | ||
627 | virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], | ||
628 | virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]); | ||
629 | |||
630 | if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) { | ||
631 | d_printf(5, dev, "WSSID from neighbor frame matches local " | ||
632 | "active WSS.\n"); | ||
633 | /* Update EDA cache */ | ||
634 | result = wlp_eda_update_node(&wlp->eda, dev_addr, wss, | ||
635 | (void *) virt_addr->data, *tag, | ||
636 | WLP_WSS_CONNECTED); | ||
637 | if (result < 0) | ||
638 | dev_err(dev, "WLP: Unable to update EDA cache " | ||
639 | "with new connected neighbor information.\n"); | ||
640 | } else { | ||
641 | dev_err(dev, "WLP: Neighbor does not have matching " | ||
642 | "WSSID.\n"); | ||
643 | result = -EINVAL; | ||
644 | } | ||
645 | |||
646 | d_fnend(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual " | ||
647 | "%02x:%02x:%02x:%02x:%02x:%02x, result = %d \n", | ||
648 | wlp, wss, buf, *tag, | ||
649 | virt_addr->data[0], virt_addr->data[1], virt_addr->data[2], | ||
650 | virt_addr->data[3], virt_addr->data[4], virt_addr->data[5], | ||
651 | result); | ||
652 | |||
653 | return result; | ||
654 | } | ||
655 | |||
656 | /** | ||
657 | * Connect to WSS neighbor | ||
658 | * | ||
659 | * Use C3/C4 exchange to determine if neighbor has WSS activated and | ||
660 | * retrieve the WSS tag and virtual EUI-48 of the neighbor. | ||
661 | */ | ||
662 | static | ||
663 | int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss, | ||
664 | struct uwb_dev_addr *dev_addr) | ||
665 | { | ||
666 | int result; | ||
667 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
668 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
669 | struct wlp_uuid wssid; | ||
670 | u8 tag; | ||
671 | struct uwb_mac_addr virt_addr; | ||
672 | DECLARE_COMPLETION_ONSTACK(completion); | ||
673 | struct wlp_session session; | ||
674 | struct wlp_frame_assoc *resp; | ||
675 | struct sk_buff *skb; | ||
676 | |||
677 | wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); | ||
678 | d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", | ||
679 | wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); | ||
680 | mutex_lock(&wlp->mutex); | ||
681 | /* Send C3 association frame */ | ||
682 | result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3); | ||
683 | if (result < 0) { | ||
684 | dev_err(dev, "Unable to send C3 frame to neighbor " | ||
685 | "%02x:%02x (%d)\n", dev_addr->data[1], | ||
686 | dev_addr->data[0], result); | ||
687 | goto out; | ||
688 | } | ||
689 | /* Create session, wait for response */ | ||
690 | session.exp_message = WLP_ASSOC_C4; | ||
691 | session.cb = wlp_session_cb; | ||
692 | session.cb_priv = &completion; | ||
693 | session.neighbor_addr = *dev_addr; | ||
694 | BUG_ON(wlp->session != NULL); | ||
695 | wlp->session = &session; | ||
696 | /* Wait for C4/F0 frame */ | ||
697 | result = wait_for_completion_interruptible_timeout(&completion, | ||
698 | WLP_PER_MSG_TIMEOUT * HZ); | ||
699 | if (result == 0) { | ||
700 | dev_err(dev, "Timeout while sending C3 to neighbor " | ||
701 | "%02x:%02x.\n", dev_addr->data[1], | ||
702 | dev_addr->data[0]); | ||
703 | result = -ETIMEDOUT; | ||
704 | goto out; | ||
705 | } | ||
706 | if (result < 0) { | ||
707 | dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n", | ||
708 | dev_addr->data[1], dev_addr->data[0]); | ||
709 | goto out; | ||
710 | } | ||
711 | /* Parse message in session->data: it will be either C4 or F0 */ | ||
712 | skb = session.data; | ||
713 | resp = (void *) skb->data; | ||
714 | d_printf(5, dev, "Received response to C3 frame. \n"); | ||
715 | d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len); | ||
716 | if (resp->type == WLP_ASSOC_F0) { | ||
717 | result = wlp_parse_f0(wlp, skb); | ||
718 | if (result < 0) | ||
719 | dev_err(dev, "WLP: unable to parse incoming F0 " | ||
720 | "frame from neighbor %02x:%02x.\n", | ||
721 | dev_addr->data[1], dev_addr->data[0]); | ||
722 | result = -EINVAL; | ||
723 | goto error_resp_parse; | ||
724 | } | ||
725 | result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr); | ||
726 | if (result < 0) { | ||
727 | dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n"); | ||
728 | goto error_resp_parse; | ||
729 | } | ||
730 | result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag, | ||
731 | &virt_addr); | ||
732 | if (result < 0) { | ||
733 | dev_err(dev, "WLP: Unable to activate connection to " | ||
734 | "neighbor %02x:%02x.\n", dev_addr->data[1], | ||
735 | dev_addr->data[0]); | ||
736 | goto error_resp_parse; | ||
737 | } | ||
738 | error_resp_parse: | ||
739 | kfree_skb(skb); | ||
740 | out: | ||
741 | /* Record that we unsuccessfully tried to connect to this neighbor */ | ||
742 | if (result < 0) | ||
743 | wlp_eda_update_node_state(&wlp->eda, dev_addr, | ||
744 | WLP_WSS_CONNECT_FAILED); | ||
745 | wlp->session = NULL; | ||
746 | mutex_unlock(&wlp->mutex); | ||
747 | d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", | ||
748 | wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); | ||
749 | return result; | ||
750 | } | ||
751 | |||
752 | /** | ||
753 | * Connect to neighbor with common WSS, send pending frame | ||
754 | * | ||
755 | * This function is scheduled when a frame is destined to a neighbor with | ||
756 | * which we do not have a connection. A copy of the EDA cache entry is | ||
757 | * provided - not the actual cache entry (because it is protected by a | ||
758 | * spinlock). | ||
759 | * | ||
760 | * First determine if neighbor has the same WSS activated, connect if it | ||
761 | * does. The C3/C4 exchange is dual purpose to determine if neighbor has | ||
762 | * WSS activated and proceed with the connection. | ||
763 | * | ||
764 | * The frame that triggered the connection setup is sent after connection | ||
765 | * setup. | ||
766 | * | ||
767 | * network queue is stopped - we need to restart when done | ||
768 | * | ||
769 | */ | ||
770 | static | ||
771 | void wlp_wss_connect_send(struct work_struct *ws) | ||
772 | { | ||
773 | struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws, | ||
774 | struct wlp_assoc_conn_ctx, | ||
775 | ws); | ||
776 | struct wlp *wlp = conn_ctx->wlp; | ||
777 | struct sk_buff *skb = conn_ctx->skb; | ||
778 | struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry; | ||
779 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
780 | struct wlp_wss *wss = &wlp->wss; | ||
781 | int result; | ||
782 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
783 | char buf[WLP_WSS_UUID_STRSIZE]; | ||
784 | |||
785 | mutex_lock(&wss->mutex); | ||
786 | wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid); | ||
787 | d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n", | ||
788 | wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]); | ||
789 | if (wss->state < WLP_WSS_STATE_ACTIVE) { | ||
790 | if (printk_ratelimit()) | ||
791 | dev_err(dev, "WLP: Attempting to connect with " | ||
792 | "WSS that is not active or connected.\n"); | ||
793 | dev_kfree_skb(skb); | ||
794 | goto out; | ||
795 | } | ||
796 | /* Establish connection - send C3 rcv C4 */ | ||
797 | result = wlp_wss_connect_neighbor(wlp, wss, dev_addr); | ||
798 | if (result < 0) { | ||
799 | if (printk_ratelimit()) | ||
800 | dev_err(dev, "WLP: Unable to establish connection " | ||
801 | "with neighbor %02x:%02x.\n", | ||
802 | dev_addr->data[1], dev_addr->data[0]); | ||
803 | dev_kfree_skb(skb); | ||
804 | goto out; | ||
805 | } | ||
806 | /* EDA entry changed, update the local copy being used */ | ||
807 | result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry); | ||
808 | if (result < 0) { | ||
809 | if (printk_ratelimit()) | ||
810 | dev_err(dev, "WLP: Cannot find EDA entry for " | ||
811 | "neighbor %02x:%02x \n", | ||
812 | dev_addr->data[1], dev_addr->data[0]); | ||
813 | } | ||
814 | result = wlp_wss_prep_hdr(wlp, eda_entry, skb); | ||
815 | if (result < 0) { | ||
816 | if (printk_ratelimit()) | ||
817 | dev_err(dev, "WLP: Unable to prepare frame header for " | ||
818 | "transmission (neighbor %02x:%02x). \n", | ||
819 | dev_addr->data[1], dev_addr->data[0]); | ||
820 | dev_kfree_skb(skb); | ||
821 | goto out; | ||
822 | } | ||
823 | BUG_ON(wlp->xmit_frame == NULL); | ||
824 | result = wlp->xmit_frame(wlp, skb, dev_addr); | ||
825 | if (result < 0) { | ||
826 | if (printk_ratelimit()) | ||
827 | dev_err(dev, "WLP: Unable to transmit frame: %d\n", | ||
828 | result); | ||
829 | if (result == -ENXIO) | ||
830 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
831 | /* We could try again ... */ | ||
832 | dev_kfree_skb(skb);/*we need to free if tx fails */ | ||
833 | } | ||
834 | out: | ||
835 | kfree(conn_ctx); | ||
836 | BUG_ON(wlp->start_queue == NULL); | ||
837 | wlp->start_queue(wlp); | ||
838 | mutex_unlock(&wss->mutex); | ||
839 | d_fnend(5, dev, "wlp %p, wss %p (wssid %s)\n", wlp, wss, buf); | ||
840 | } | ||
841 | |||
842 | /** | ||
843 | * Add WLP header to outgoing skb | ||
844 | * | ||
845 | * @eda_entry: pointer to neighbor's entry in the EDA cache | ||
846 | * @_skb: skb containing data destined to the neighbor | ||
847 | */ | ||
848 | int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
849 | void *_skb) | ||
850 | { | ||
851 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
852 | int result = 0; | ||
853 | unsigned char *eth_addr = eda_entry->eth_addr; | ||
854 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
855 | struct sk_buff *skb = _skb; | ||
856 | struct wlp_frame_std_abbrv_hdr *std_hdr; | ||
857 | |||
858 | d_fnstart(6, dev, "wlp %p \n", wlp); | ||
859 | if (eda_entry->state == WLP_WSS_CONNECTED) { | ||
860 | /* Add WLP header */ | ||
861 | BUG_ON(skb_headroom(skb) < sizeof(*std_hdr)); | ||
862 | std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr)); | ||
863 | std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID); | ||
864 | std_hdr->hdr.type = WLP_FRAME_STANDARD; | ||
865 | std_hdr->tag = eda_entry->wss->tag; | ||
866 | } else { | ||
867 | if (printk_ratelimit()) | ||
868 | dev_err(dev, "WLP: Destination neighbor (Ethernet: " | ||
869 | "%02x:%02x:%02x:%02x:%02x:%02x, Dev: " | ||
870 | "%02x:%02x) is not connected. \n", eth_addr[0], | ||
871 | eth_addr[1], eth_addr[2], eth_addr[3], | ||
872 | eth_addr[4], eth_addr[5], dev_addr->data[1], | ||
873 | dev_addr->data[0]); | ||
874 | result = -EINVAL; | ||
875 | } | ||
876 | d_fnend(6, dev, "wlp %p \n", wlp); | ||
877 | return result; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * Prepare skb for neighbor: connect if not already and prep WLP header | ||
883 | * | ||
884 | * This function is called in interrupt context, but it needs to sleep. We | ||
885 | * temporarily stop the net queue to establish the WLP connection. | ||
886 | * Setup of the WLP connection and restart of queue is scheduled | ||
887 | * on the default work queue. | ||
888 | * | ||
889 | * run with eda->lock held (spinlock) | ||
890 | */ | ||
891 | int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
892 | void *_skb) | ||
893 | { | ||
894 | int result = 0; | ||
895 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
896 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
897 | unsigned char *eth_addr = eda_entry->eth_addr; | ||
898 | struct sk_buff *skb = _skb; | ||
899 | struct wlp_assoc_conn_ctx *conn_ctx; | ||
900 | |||
901 | d_fnstart(5, dev, "wlp %p\n", wlp); | ||
902 | d_printf(5, dev, "To neighbor %02x:%02x with eth " | ||
903 | "%02x:%02x:%02x:%02x:%02x:%02x\n", dev_addr->data[1], | ||
904 | dev_addr->data[0], eth_addr[0], eth_addr[1], eth_addr[2], | ||
905 | eth_addr[3], eth_addr[4], eth_addr[5]); | ||
906 | if (eda_entry->state == WLP_WSS_UNCONNECTED) { | ||
907 | /* We don't want any more packets while we set up connection */ | ||
908 | BUG_ON(wlp->stop_queue == NULL); | ||
909 | wlp->stop_queue(wlp); | ||
910 | conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC); | ||
911 | if (conn_ctx == NULL) { | ||
912 | if (printk_ratelimit()) | ||
913 | dev_err(dev, "WLP: Unable to allocate memory " | ||
914 | "for connection handling.\n"); | ||
915 | result = -ENOMEM; | ||
916 | goto out; | ||
917 | } | ||
918 | conn_ctx->wlp = wlp; | ||
919 | conn_ctx->skb = skb; | ||
920 | conn_ctx->eda_entry = *eda_entry; | ||
921 | INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send); | ||
922 | schedule_work(&conn_ctx->ws); | ||
923 | result = 1; | ||
924 | } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) { | ||
925 | /* Previous connection attempts failed, don't retry - see | ||
926 | * conditions for connection in WLP 0.99 [7.6.2] */ | ||
927 | if (printk_ratelimit()) | ||
928 | dev_err(dev, "Could not connect to neighbor " | ||
929 | "previously. Not retrying. \n"); | ||
930 | result = -ENONET; | ||
931 | goto out; | ||
932 | } else { /* eda_entry->state == WLP_WSS_CONNECTED */ | ||
933 | d_printf(5, dev, "Neighbor is connected, preparing frame.\n"); | ||
934 | result = wlp_wss_prep_hdr(wlp, eda_entry, skb); | ||
935 | } | ||
936 | out: | ||
937 | d_fnend(5, dev, "wlp %p, result = %d \n", wlp, result); | ||
938 | return result; | ||
939 | } | ||
940 | |||
941 | /** | ||
942 | * Emulate broadcast: copy skb, send copy to neighbor (connect if not already) | ||
943 | * | ||
944 | * We need to copy skbs in the case where we emulate broadcast through | ||
945 | * unicast. We copy instead of clone because we are modifying the data of | ||
946 | * the frame after copying ... clones share data so we cannot emulate | ||
947 | * broadcast using clones. | ||
948 | * | ||
949 | * run with eda->lock held (spinlock) | ||
950 | */ | ||
951 | int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry, | ||
952 | void *_skb) | ||
953 | { | ||
954 | int result = -ENOMEM; | ||
955 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
956 | struct sk_buff *skb = _skb; | ||
957 | struct sk_buff *copy; | ||
958 | struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr; | ||
959 | |||
960 | d_fnstart(5, dev, "to neighbor %02x:%02x, skb (%p) \n", | ||
961 | dev_addr->data[1], dev_addr->data[0], skb); | ||
962 | copy = skb_copy(skb, GFP_ATOMIC); | ||
963 | if (copy == NULL) { | ||
964 | if (printk_ratelimit()) | ||
965 | dev_err(dev, "WLP: Unable to copy skb for " | ||
966 | "transmission.\n"); | ||
967 | goto out; | ||
968 | } | ||
969 | result = wlp_wss_connect_prep(wlp, eda_entry, copy); | ||
970 | if (result < 0) { | ||
971 | if (printk_ratelimit()) | ||
972 | dev_err(dev, "WLP: Unable to connect/send skb " | ||
973 | "to neighbor.\n"); | ||
974 | dev_kfree_skb_irq(copy); | ||
975 | goto out; | ||
976 | } else if (result == 1) | ||
977 | /* Frame will be transmitted separately */ | ||
978 | goto out; | ||
979 | BUG_ON(wlp->xmit_frame == NULL); | ||
980 | result = wlp->xmit_frame(wlp, copy, dev_addr); | ||
981 | if (result < 0) { | ||
982 | if (printk_ratelimit()) | ||
983 | dev_err(dev, "WLP: Unable to transmit frame: %d\n", | ||
984 | result); | ||
985 | if ((result == -ENXIO) && printk_ratelimit()) | ||
986 | dev_err(dev, "WLP: Is network interface up? \n"); | ||
987 | /* We could try again ... */ | ||
988 | dev_kfree_skb_irq(copy);/*we need to free if tx fails */ | ||
989 | } | ||
990 | out: | ||
991 | d_fnend(5, dev, "to neighbor %02x:%02x \n", dev_addr->data[1], | ||
992 | dev_addr->data[0]); | ||
993 | return result; | ||
994 | } | ||
995 | |||
996 | |||
997 | /** | ||
998 | * Setup WSS | ||
999 | * | ||
1000 | * Should be called by network driver after the interface has been given a | ||
1001 | * MAC address. | ||
1002 | */ | ||
1003 | int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss) | ||
1004 | { | ||
1005 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
1006 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1007 | int result = 0; | ||
1008 | d_fnstart(5, dev, "wss (%p) \n", wss); | ||
1009 | mutex_lock(&wss->mutex); | ||
1010 | wss->kobj.parent = &net_dev->dev.kobj; | ||
1011 | if (!is_valid_ether_addr(net_dev->dev_addr)) { | ||
1012 | dev_err(dev, "WLP: Invalid MAC address. Cannot use for" | ||
1013 | "virtual.\n"); | ||
1014 | result = -EINVAL; | ||
1015 | goto out; | ||
1016 | } | ||
1017 | memcpy(wss->virtual_addr.data, net_dev->dev_addr, | ||
1018 | sizeof(wss->virtual_addr.data)); | ||
1019 | out: | ||
1020 | mutex_unlock(&wss->mutex); | ||
1021 | d_fnend(5, dev, "wss (%p) \n", wss); | ||
1022 | return result; | ||
1023 | } | ||
1024 | EXPORT_SYMBOL_GPL(wlp_wss_setup); | ||
1025 | |||
1026 | /** | ||
1027 | * Remove WSS | ||
1028 | * | ||
1029 | * Called by client that configured WSS through wlp_wss_setup(). This | ||
1030 | * function is called when client no longer needs WSS, eg. client shuts | ||
1031 | * down. | ||
1032 | * | ||
1033 | * We remove the WLP IE from the beacon before initiating local cleanup. | ||
1034 | */ | ||
1035 | void wlp_wss_remove(struct wlp_wss *wss) | ||
1036 | { | ||
1037 | struct wlp *wlp = container_of(wss, struct wlp, wss); | ||
1038 | struct device *dev = &wlp->rc->uwb_dev.dev; | ||
1039 | d_fnstart(5, dev, "wss (%p) \n", wss); | ||
1040 | mutex_lock(&wss->mutex); | ||
1041 | if (wss->state == WLP_WSS_STATE_ACTIVE) | ||
1042 | uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP); | ||
1043 | if (wss->state != WLP_WSS_STATE_NONE) { | ||
1044 | sysfs_remove_group(&wss->kobj, &wss_attr_group); | ||
1045 | kobject_put(&wss->kobj); | ||
1046 | } | ||
1047 | wss->kobj.parent = NULL; | ||
1048 | memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr)); | ||
1049 | /* Cleanup EDA cache */ | ||
1050 | wlp_eda_release(&wlp->eda); | ||
1051 | wlp_eda_init(&wlp->eda); | ||
1052 | mutex_unlock(&wss->mutex); | ||
1053 | d_fnend(5, dev, "wss (%p) \n", wss); | ||
1054 | } | ||
1055 | EXPORT_SYMBOL_GPL(wlp_wss_remove); | ||
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 1abfe664c444..a08c33a26ca9 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h | |||
@@ -129,6 +129,7 @@ extern void bitmap_fold(unsigned long *dst, const unsigned long *orig, | |||
129 | extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); | 129 | extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); |
130 | extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); | 130 | extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); |
131 | extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); | 131 | extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); |
132 | extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits); | ||
132 | 133 | ||
133 | #define BITMAP_LAST_WORD_MASK(nbits) \ | 134 | #define BITMAP_LAST_WORD_MASK(nbits) \ |
134 | ( \ | 135 | ( \ |
diff --git a/include/linux/usb/wusb-wa.h b/include/linux/usb/wusb-wa.h new file mode 100644 index 000000000000..a102561e7026 --- /dev/null +++ b/include/linux/usb/wusb-wa.h | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Wireless USB Wire Adapter constants and structures. | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation. | ||
5 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * FIXME: docs | ||
23 | * FIXME: organize properly, group logically | ||
24 | * | ||
25 | * All the event structures are defined in uwb/spec.h, as they are | ||
26 | * common to the WHCI and WUSB radio control interfaces. | ||
27 | * | ||
28 | * References: | ||
29 | * [WUSB] Wireless Universal Serial Bus Specification, revision 1.0, ch8 | ||
30 | */ | ||
31 | #ifndef __LINUX_USB_WUSB_WA_H | ||
32 | #define __LINUX_USB_WUSB_WA_H | ||
33 | |||
34 | /** | ||
35 | * Radio Command Request for the Radio Control Interface | ||
36 | * | ||
37 | * Radio Control Interface command and event codes are the same as | ||
38 | * WHCI, and listed in include/linux/uwb.h:UWB_RC_{CMD,EVT}_* | ||
39 | */ | ||
40 | enum { | ||
41 | WA_EXEC_RC_CMD = 40, /* Radio Control command Request */ | ||
42 | }; | ||
43 | |||
44 | /* Wireless Adapter Requests ([WUSB] table 8-51) */ | ||
45 | enum { | ||
46 | WUSB_REQ_ADD_MMC_IE = 20, | ||
47 | WUSB_REQ_REMOVE_MMC_IE = 21, | ||
48 | WUSB_REQ_SET_NUM_DNTS = 22, | ||
49 | WUSB_REQ_SET_CLUSTER_ID = 23, | ||
50 | WUSB_REQ_SET_DEV_INFO = 24, | ||
51 | WUSB_REQ_GET_TIME = 25, | ||
52 | WUSB_REQ_SET_STREAM_IDX = 26, | ||
53 | WUSB_REQ_SET_WUSB_MAS = 27, | ||
54 | }; | ||
55 | |||
56 | |||
57 | /* Wireless Adapter WUSB Channel Time types ([WUSB] table 8-52) */ | ||
58 | enum { | ||
59 | WUSB_TIME_ADJ = 0, | ||
60 | WUSB_TIME_BPST = 1, | ||
61 | WUSB_TIME_WUSB = 2, | ||
62 | }; | ||
63 | |||
64 | enum { | ||
65 | WA_ENABLE = 0x01, | ||
66 | WA_RESET = 0x02, | ||
67 | RPIPE_PAUSE = 0x1, | ||
68 | }; | ||
69 | |||
70 | /* Responses from Get Status request ([WUSB] section 8.3.1.6) */ | ||
71 | enum { | ||
72 | WA_STATUS_ENABLED = 0x01, | ||
73 | WA_STATUS_RESETTING = 0x02 | ||
74 | }; | ||
75 | |||
76 | enum rpipe_crs { | ||
77 | RPIPE_CRS_CTL = 0x01, | ||
78 | RPIPE_CRS_ISO = 0x02, | ||
79 | RPIPE_CRS_BULK = 0x04, | ||
80 | RPIPE_CRS_INTR = 0x08 | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * RPipe descriptor ([WUSB] section 8.5.2.11) | ||
85 | * | ||
86 | * FIXME: explain rpipes | ||
87 | */ | ||
88 | struct usb_rpipe_descriptor { | ||
89 | u8 bLength; | ||
90 | u8 bDescriptorType; | ||
91 | __le16 wRPipeIndex; | ||
92 | __le16 wRequests; | ||
93 | __le16 wBlocks; /* rw if 0 */ | ||
94 | __le16 wMaxPacketSize; /* rw? */ | ||
95 | u8 bHSHubAddress; /* reserved: 0 */ | ||
96 | u8 bHSHubPort; /* ??? FIXME ??? */ | ||
97 | u8 bSpeed; /* rw: xfer rate 'enum uwb_phy_rate' */ | ||
98 | u8 bDeviceAddress; /* rw: Target device address */ | ||
99 | u8 bEndpointAddress; /* rw: Target EP address */ | ||
100 | u8 bDataSequence; /* ro: Current Data sequence */ | ||
101 | __le32 dwCurrentWindow; /* ro */ | ||
102 | u8 bMaxDataSequence; /* ro?: max supported seq */ | ||
103 | u8 bInterval; /* rw: */ | ||
104 | u8 bOverTheAirInterval; /* rw: */ | ||
105 | u8 bmAttribute; /* ro? */ | ||
106 | u8 bmCharacteristics; /* ro? enum rpipe_attr, supported xsactions */ | ||
107 | u8 bmRetryOptions; /* rw? */ | ||
108 | __le16 wNumTransactionErrors; /* rw */ | ||
109 | } __attribute__ ((packed)); | ||
110 | |||
111 | /** | ||
112 | * Wire Adapter Notification types ([WUSB] sections 8.4.5 & 8.5.4) | ||
113 | * | ||
114 | * These are the notifications coming on the notification endpoint of | ||
115 | * an HWA and a DWA. | ||
116 | */ | ||
117 | enum wa_notif_type { | ||
118 | DWA_NOTIF_RWAKE = 0x91, | ||
119 | DWA_NOTIF_PORTSTATUS = 0x92, | ||
120 | WA_NOTIF_TRANSFER = 0x93, | ||
121 | HWA_NOTIF_BPST_ADJ = 0x94, | ||
122 | HWA_NOTIF_DN = 0x95, | ||
123 | }; | ||
124 | |||
125 | /** | ||
126 | * Wire Adapter notification header | ||
127 | * | ||
128 | * Notifications coming from a wire adapter use a common header | ||
129 | * defined in [WUSB] sections 8.4.5 & 8.5.4. | ||
130 | */ | ||
131 | struct wa_notif_hdr { | ||
132 | u8 bLength; | ||
133 | u8 bNotifyType; /* enum wa_notif_type */ | ||
134 | } __attribute__((packed)); | ||
135 | |||
136 | /** | ||
137 | * HWA DN Received notification [(WUSB] section 8.5.4.2) | ||
138 | * | ||
139 | * The DNData is specified in WUSB1.0[7.6]. For each device | ||
140 | * notification we received, we just need to dispatch it. | ||
141 | * | ||
142 | * @dndata: this is really an array of notifications, but all start | ||
143 | * with the same header. | ||
144 | */ | ||
145 | struct hwa_notif_dn { | ||
146 | struct wa_notif_hdr hdr; | ||
147 | u8 bSourceDeviceAddr; /* from errata 2005/07 */ | ||
148 | u8 bmAttributes; | ||
149 | struct wusb_dn_hdr dndata[]; | ||
150 | } __attribute__((packed)); | ||
151 | |||
152 | /* [WUSB] section 8.3.3 */ | ||
153 | enum wa_xfer_type { | ||
154 | WA_XFER_TYPE_CTL = 0x80, | ||
155 | WA_XFER_TYPE_BI = 0x81, /* bulk/interrupt */ | ||
156 | WA_XFER_TYPE_ISO = 0x82, | ||
157 | WA_XFER_RESULT = 0x83, | ||
158 | WA_XFER_ABORT = 0x84, | ||
159 | }; | ||
160 | |||
161 | /* [WUSB] section 8.3.3 */ | ||
162 | struct wa_xfer_hdr { | ||
163 | u8 bLength; /* 0x18 */ | ||
164 | u8 bRequestType; /* 0x80 WA_REQUEST_TYPE_CTL */ | ||
165 | __le16 wRPipe; /* RPipe index */ | ||
166 | __le32 dwTransferID; /* Host-assigned ID */ | ||
167 | __le32 dwTransferLength; /* Length of data to xfer */ | ||
168 | u8 bTransferSegment; | ||
169 | } __attribute__((packed)); | ||
170 | |||
171 | struct wa_xfer_ctl { | ||
172 | struct wa_xfer_hdr hdr; | ||
173 | u8 bmAttribute; | ||
174 | __le16 wReserved; | ||
175 | struct usb_ctrlrequest baSetupData; | ||
176 | } __attribute__((packed)); | ||
177 | |||
178 | struct wa_xfer_bi { | ||
179 | struct wa_xfer_hdr hdr; | ||
180 | u8 bReserved; | ||
181 | __le16 wReserved; | ||
182 | } __attribute__((packed)); | ||
183 | |||
184 | struct wa_xfer_hwaiso { | ||
185 | struct wa_xfer_hdr hdr; | ||
186 | u8 bReserved; | ||
187 | __le16 wPresentationTime; | ||
188 | __le32 dwNumOfPackets; | ||
189 | /* FIXME: u8 pktdata[]? */ | ||
190 | } __attribute__((packed)); | ||
191 | |||
192 | /* [WUSB] section 8.3.3.5 */ | ||
193 | struct wa_xfer_abort { | ||
194 | u8 bLength; | ||
195 | u8 bRequestType; | ||
196 | __le16 wRPipe; /* RPipe index */ | ||
197 | __le32 dwTransferID; /* Host-assigned ID */ | ||
198 | } __attribute__((packed)); | ||
199 | |||
200 | /** | ||
201 | * WA Transfer Complete notification ([WUSB] section 8.3.3.3) | ||
202 | * | ||
203 | */ | ||
204 | struct wa_notif_xfer { | ||
205 | struct wa_notif_hdr hdr; | ||
206 | u8 bEndpoint; | ||
207 | u8 Reserved; | ||
208 | } __attribute__((packed)); | ||
209 | |||
210 | /** Transfer result basic codes [WUSB] table 8-15 */ | ||
211 | enum { | ||
212 | WA_XFER_STATUS_SUCCESS, | ||
213 | WA_XFER_STATUS_HALTED, | ||
214 | WA_XFER_STATUS_DATA_BUFFER_ERROR, | ||
215 | WA_XFER_STATUS_BABBLE, | ||
216 | WA_XFER_RESERVED, | ||
217 | WA_XFER_STATUS_NOT_FOUND, | ||
218 | WA_XFER_STATUS_INSUFFICIENT_RESOURCE, | ||
219 | WA_XFER_STATUS_TRANSACTION_ERROR, | ||
220 | WA_XFER_STATUS_ABORTED, | ||
221 | WA_XFER_STATUS_RPIPE_NOT_READY, | ||
222 | WA_XFER_INVALID_FORMAT, | ||
223 | WA_XFER_UNEXPECTED_SEGMENT_NUMBER, | ||
224 | WA_XFER_STATUS_RPIPE_TYPE_MISMATCH, | ||
225 | }; | ||
226 | |||
227 | /** [WUSB] section 8.3.3.4 */ | ||
228 | struct wa_xfer_result { | ||
229 | struct wa_notif_hdr hdr; | ||
230 | __le32 dwTransferID; | ||
231 | __le32 dwTransferLength; | ||
232 | u8 bTransferSegment; | ||
233 | u8 bTransferStatus; | ||
234 | __le32 dwNumOfPackets; | ||
235 | } __attribute__((packed)); | ||
236 | |||
237 | /** | ||
238 | * Wire Adapter Class Descriptor ([WUSB] section 8.5.2.7). | ||
239 | * | ||
240 | * NOTE: u16 fields are read Little Endian from the hardware. | ||
241 | * | ||
242 | * @bNumPorts is the original max number of devices that the host can | ||
243 | * connect; we might chop this so the stack can handle | ||
244 | * it. In case you need to access it, use wusbhc->ports_max | ||
245 | * if it is a Wireless USB WA. | ||
246 | */ | ||
247 | struct usb_wa_descriptor { | ||
248 | u8 bLength; | ||
249 | u8 bDescriptorType; | ||
250 | u16 bcdWAVersion; | ||
251 | u8 bNumPorts; /* don't use!! */ | ||
252 | u8 bmAttributes; /* Reserved == 0 */ | ||
253 | u16 wNumRPipes; | ||
254 | u16 wRPipeMaxBlock; | ||
255 | u8 bRPipeBlockSize; | ||
256 | u8 bPwrOn2PwrGood; | ||
257 | u8 bNumMMCIEs; | ||
258 | u8 DeviceRemovable; /* FIXME: in DWA this is up to 16 bytes */ | ||
259 | } __attribute__((packed)); | ||
260 | |||
261 | /** | ||
262 | * HWA Device Information Buffer (WUSB1.0[T8.54]) | ||
263 | */ | ||
264 | struct hwa_dev_info { | ||
265 | u8 bmDeviceAvailability[32]; /* FIXME: ignored for now */ | ||
266 | u8 bDeviceAddress; | ||
267 | __le16 wPHYRates; | ||
268 | u8 bmDeviceAttribute; | ||
269 | } __attribute__((packed)); | ||
270 | |||
271 | #endif /* #ifndef __LINUX_USB_WUSB_WA_H */ | ||
diff --git a/include/linux/usb/wusb.h b/include/linux/usb/wusb.h new file mode 100644 index 000000000000..5f401b644ed5 --- /dev/null +++ b/include/linux/usb/wusb.h | |||
@@ -0,0 +1,376 @@ | |||
1 | /* | ||
2 | * Wireless USB Standard Definitions | ||
3 | * Event Size Tables | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * FIXME: organize properly, group logically | ||
25 | * | ||
26 | * All the event structures are defined in uwb/spec.h, as they are | ||
27 | * common to the WHCI and WUSB radio control interfaces. | ||
28 | */ | ||
29 | |||
30 | #ifndef __WUSB_H__ | ||
31 | #define __WUSB_H__ | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/uwb/spec.h> | ||
36 | #include <linux/usb/ch9.h> | ||
37 | #include <linux/param.h> | ||
38 | |||
39 | /** | ||
40 | * WUSB Information Element header | ||
41 | * | ||
42 | * I don't know why, they decided to make it different to the MBOA MAC | ||
43 | * IE Header; beats me. | ||
44 | */ | ||
45 | struct wuie_hdr { | ||
46 | u8 bLength; | ||
47 | u8 bIEIdentifier; | ||
48 | } __attribute__((packed)); | ||
49 | |||
50 | enum { | ||
51 | WUIE_ID_WCTA = 0x80, | ||
52 | WUIE_ID_CONNECTACK, | ||
53 | WUIE_ID_HOST_INFO, | ||
54 | WUIE_ID_CHANGE_ANNOUNCE, | ||
55 | WUIE_ID_DEVICE_DISCONNECT, | ||
56 | WUIE_ID_HOST_DISCONNECT, | ||
57 | WUIE_ID_KEEP_ALIVE = 0x89, | ||
58 | WUIE_ID_ISOCH_DISCARD, | ||
59 | WUIE_ID_RESET_DEVICE, | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * Maximum number of array elements in a WUSB IE. | ||
64 | * | ||
65 | * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that | ||
66 | * are "arrays" have to limited to 4 elements. So we define it | ||
67 | * like that to ease up and submit only the neeed size. | ||
68 | */ | ||
69 | #define WUIE_ELT_MAX 4 | ||
70 | |||
71 | /** | ||
72 | * Wrapper for the data that defines a CHID, a CDID or a CK | ||
73 | * | ||
74 | * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of | ||
75 | * data. In order to avoid confusion and enforce types, we wrap it. | ||
76 | * | ||
77 | * Make it packed, as we use it in some hw defintions. | ||
78 | */ | ||
79 | struct wusb_ckhdid { | ||
80 | u8 data[16]; | ||
81 | } __attribute__((packed)); | ||
82 | |||
83 | const static | ||
84 | struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } }; | ||
85 | |||
86 | #define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1) | ||
87 | |||
88 | /** | ||
89 | * WUSB IE: Host Information (WUSB1.0[7.5.2]) | ||
90 | * | ||
91 | * Used to provide information about the host to the Wireless USB | ||
92 | * devices in range (CHID can be used as an ASCII string). | ||
93 | */ | ||
94 | struct wuie_host_info { | ||
95 | struct wuie_hdr hdr; | ||
96 | __le16 attributes; | ||
97 | struct wusb_ckhdid CHID; | ||
98 | } __attribute__((packed)); | ||
99 | |||
100 | /** | ||
101 | * WUSB IE: Connect Ack (WUSB1.0[7.5.1]) | ||
102 | * | ||
103 | * Used to acknowledge device connect requests. See note for | ||
104 | * WUIE_ELT_MAX. | ||
105 | */ | ||
106 | struct wuie_connect_ack { | ||
107 | struct wuie_hdr hdr; | ||
108 | struct { | ||
109 | struct wusb_ckhdid CDID; | ||
110 | u8 bDeviceAddress; /* 0 means unused */ | ||
111 | u8 bReserved; | ||
112 | } blk[WUIE_ELT_MAX]; | ||
113 | } __attribute__((packed)); | ||
114 | |||
115 | /** | ||
116 | * WUSB IE Host Information Element, Connect Availability | ||
117 | * | ||
118 | * WUSB1.0[7.5.2], bmAttributes description | ||
119 | */ | ||
120 | enum { | ||
121 | WUIE_HI_CAP_RECONNECT = 0, | ||
122 | WUIE_HI_CAP_LIMITED, | ||
123 | WUIE_HI_CAP_RESERVED, | ||
124 | WUIE_HI_CAP_ALL, | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * WUSB IE: Channel Stop (WUSB1.0[7.5.8]) | ||
129 | * | ||
130 | * Tells devices the host is going to stop sending MMCs and will dissapear. | ||
131 | */ | ||
132 | struct wuie_channel_stop { | ||
133 | struct wuie_hdr hdr; | ||
134 | u8 attributes; | ||
135 | u8 timestamp[3]; | ||
136 | } __attribute__((packed)); | ||
137 | |||
138 | /** | ||
139 | * WUSB IE: Keepalive (WUSB1.0[7.5.9]) | ||
140 | * | ||
141 | * Ask device(s) to send keepalives. | ||
142 | */ | ||
143 | struct wuie_keep_alive { | ||
144 | struct wuie_hdr hdr; | ||
145 | u8 bDeviceAddress[WUIE_ELT_MAX]; | ||
146 | } __attribute__((packed)); | ||
147 | |||
148 | /** | ||
149 | * WUSB IE: Reset device (WUSB1.0[7.5.11]) | ||
150 | * | ||
151 | * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only | ||
152 | * use it for one at the time... | ||
153 | * | ||
154 | * In any case, this request is a wee bit silly: why don't they target | ||
155 | * by address?? | ||
156 | */ | ||
157 | struct wuie_reset { | ||
158 | struct wuie_hdr hdr; | ||
159 | struct wusb_ckhdid CDID; | ||
160 | } __attribute__((packed)); | ||
161 | |||
162 | /** | ||
163 | * WUSB IE: Disconnect device (WUSB1.0[7.5.11]) | ||
164 | * | ||
165 | * Tell device to disconnect; we can fit 4 addresses, but we only use | ||
166 | * it for one at the time... | ||
167 | */ | ||
168 | struct wuie_disconnect { | ||
169 | struct wuie_hdr hdr; | ||
170 | u8 bDeviceAddress; | ||
171 | u8 padding; | ||
172 | } __attribute__((packed)); | ||
173 | |||
174 | /** | ||
175 | * WUSB IE: Host disconnect ([WUSB] section 7.5.5) | ||
176 | * | ||
177 | * Tells all connected devices to disconnect. | ||
178 | */ | ||
179 | struct wuie_host_disconnect { | ||
180 | struct wuie_hdr hdr; | ||
181 | } __attribute__((packed)); | ||
182 | |||
183 | /** | ||
184 | * WUSB Device Notification header (WUSB1.0[7.6]) | ||
185 | */ | ||
186 | struct wusb_dn_hdr { | ||
187 | u8 bType; | ||
188 | u8 notifdata[]; | ||
189 | } __attribute__((packed)); | ||
190 | |||
191 | /** Device Notification codes (WUSB1.0[Table 7-54]) */ | ||
192 | enum WUSB_DN { | ||
193 | WUSB_DN_CONNECT = 0x01, | ||
194 | WUSB_DN_DISCONNECT = 0x02, | ||
195 | WUSB_DN_EPRDY = 0x03, | ||
196 | WUSB_DN_MASAVAILCHANGED = 0x04, | ||
197 | WUSB_DN_RWAKE = 0x05, | ||
198 | WUSB_DN_SLEEP = 0x06, | ||
199 | WUSB_DN_ALIVE = 0x07, | ||
200 | }; | ||
201 | |||
202 | /** WUSB Device Notification Connect */ | ||
203 | struct wusb_dn_connect { | ||
204 | struct wusb_dn_hdr hdr; | ||
205 | __le16 attributes; | ||
206 | struct wusb_ckhdid CDID; | ||
207 | } __attribute__((packed)); | ||
208 | |||
209 | static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn) | ||
210 | { | ||
211 | return le16_to_cpu(dn->attributes) & 0xff; | ||
212 | } | ||
213 | |||
214 | static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn) | ||
215 | { | ||
216 | return (le16_to_cpu(dn->attributes) >> 8) & 0x1; | ||
217 | } | ||
218 | |||
219 | static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn) | ||
220 | { | ||
221 | return (le16_to_cpu(dn->attributes) >> 9) & 0x03; | ||
222 | } | ||
223 | |||
224 | /** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */ | ||
225 | struct wusb_dn_alive { | ||
226 | struct wusb_dn_hdr hdr; | ||
227 | } __attribute__((packed)); | ||
228 | |||
229 | /** Device is disconnecting (WUSB1.0[7.6.2]) */ | ||
230 | struct wusb_dn_disconnect { | ||
231 | struct wusb_dn_hdr hdr; | ||
232 | } __attribute__((packed)); | ||
233 | |||
234 | /* General constants */ | ||
235 | enum { | ||
236 | WUSB_TRUST_TIMEOUT_MS = 4000, /* [WUSB] section 4.15.1 */ | ||
237 | }; | ||
238 | |||
239 | static inline size_t ckhdid_printf(char *pr_ckhdid, size_t size, | ||
240 | const struct wusb_ckhdid *ckhdid) | ||
241 | { | ||
242 | return scnprintf(pr_ckhdid, size, | ||
243 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx " | ||
244 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx", | ||
245 | ckhdid->data[0], ckhdid->data[1], | ||
246 | ckhdid->data[2], ckhdid->data[3], | ||
247 | ckhdid->data[4], ckhdid->data[5], | ||
248 | ckhdid->data[6], ckhdid->data[7], | ||
249 | ckhdid->data[8], ckhdid->data[9], | ||
250 | ckhdid->data[10], ckhdid->data[11], | ||
251 | ckhdid->data[12], ckhdid->data[13], | ||
252 | ckhdid->data[14], ckhdid->data[15]); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * WUSB Crypto stuff (WUSB1.0[6]) | ||
257 | */ | ||
258 | |||
259 | extern const char *wusb_et_name(u8); | ||
260 | |||
261 | /** | ||
262 | * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for | ||
263 | * the host or the device. | ||
264 | */ | ||
265 | static inline u8 wusb_key_index(int index, int type, int originator) | ||
266 | { | ||
267 | return (originator << 6) | (type << 4) | index; | ||
268 | } | ||
269 | |||
270 | #define WUSB_KEY_INDEX_TYPE_PTK 0 /* for HWA only */ | ||
271 | #define WUSB_KEY_INDEX_TYPE_ASSOC 1 | ||
272 | #define WUSB_KEY_INDEX_TYPE_GTK 2 | ||
273 | #define WUSB_KEY_INDEX_ORIGINATOR_HOST 0 | ||
274 | #define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1 | ||
275 | |||
276 | /* A CCM Nonce, defined in WUSB1.0[6.4.1] */ | ||
277 | struct aes_ccm_nonce { | ||
278 | u8 sfn[6]; /* Little Endian */ | ||
279 | u8 tkid[3]; /* LE */ | ||
280 | struct uwb_dev_addr dest_addr; | ||
281 | struct uwb_dev_addr src_addr; | ||
282 | } __attribute__((packed)); | ||
283 | |||
284 | /* A CCM operation label, defined on WUSB1.0[6.5.x] */ | ||
285 | struct aes_ccm_label { | ||
286 | u8 data[14]; | ||
287 | } __attribute__((packed)); | ||
288 | |||
289 | /* | ||
290 | * Input to the key derivation sequence defined in | ||
291 | * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the | ||
292 | * PRF function. | ||
293 | */ | ||
294 | struct wusb_keydvt_in { | ||
295 | u8 hnonce[16]; | ||
296 | u8 dnonce[16]; | ||
297 | } __attribute__((packed)); | ||
298 | |||
299 | /* | ||
300 | * Output from the key derivation sequence defined in | ||
301 | * WUSB1.0[6.5.1]. | ||
302 | */ | ||
303 | struct wusb_keydvt_out { | ||
304 | u8 kck[16]; | ||
305 | u8 ptk[16]; | ||
306 | } __attribute__((packed)); | ||
307 | |||
308 | /* Pseudo Random Function WUSB1.0[6.5] */ | ||
309 | extern int wusb_crypto_init(void); | ||
310 | extern void wusb_crypto_exit(void); | ||
311 | extern ssize_t wusb_prf(void *out, size_t out_size, | ||
312 | const u8 key[16], const struct aes_ccm_nonce *_n, | ||
313 | const struct aes_ccm_label *a, | ||
314 | const void *b, size_t blen, size_t len); | ||
315 | |||
316 | static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16], | ||
317 | const struct aes_ccm_nonce *n, | ||
318 | const struct aes_ccm_label *a, | ||
319 | const void *b, size_t blen) | ||
320 | { | ||
321 | return wusb_prf(out, out_size, key, n, a, b, blen, 64); | ||
322 | } | ||
323 | |||
324 | static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16], | ||
325 | const struct aes_ccm_nonce *n, | ||
326 | const struct aes_ccm_label *a, | ||
327 | const void *b, size_t blen) | ||
328 | { | ||
329 | return wusb_prf(out, out_size, key, n, a, b, blen, 128); | ||
330 | } | ||
331 | |||
332 | static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16], | ||
333 | const struct aes_ccm_nonce *n, | ||
334 | const struct aes_ccm_label *a, | ||
335 | const void *b, size_t blen) | ||
336 | { | ||
337 | return wusb_prf(out, out_size, key, n, a, b, blen, 256); | ||
338 | } | ||
339 | |||
340 | /* Key derivation WUSB1.0[6.5.1] */ | ||
341 | static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out, | ||
342 | const u8 key[16], | ||
343 | const struct aes_ccm_nonce *n, | ||
344 | const struct wusb_keydvt_in *keydvt_in) | ||
345 | { | ||
346 | const struct aes_ccm_label a = { .data = "Pair-wise keys" }; | ||
347 | return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a, | ||
348 | keydvt_in, sizeof(*keydvt_in)); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Out-of-band MIC Generation WUSB1.0[6.5.2] | ||
353 | * | ||
354 | * Compute the MIC over @key, @n and @hs and place it in @mic_out. | ||
355 | * | ||
356 | * @mic_out: Where to place the 8 byte MIC tag | ||
357 | * @key: KCK from the derivation process | ||
358 | * @n: CCM nonce, n->sfn == 0, TKID as established in the | ||
359 | * process. | ||
360 | * @hs: Handshake struct for phase 2 of the 4-way. | ||
361 | * hs->bStatus and hs->bReserved are zero. | ||
362 | * hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2] | ||
363 | * hs->dest_addr is the device's USB address padded with 0 | ||
364 | * hs->src_addr is the hosts's UWB device address | ||
365 | * hs->mic is ignored (as we compute that value). | ||
366 | */ | ||
367 | static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16], | ||
368 | const struct aes_ccm_nonce *n, | ||
369 | const struct usb_handshake *hs) | ||
370 | { | ||
371 | const struct aes_ccm_label a = { .data = "out-of-bandMIC" }; | ||
372 | return wusb_prf_64(mic_out, 8, key, n, &a, | ||
373 | hs, sizeof(*hs) - sizeof(hs->MIC)); | ||
374 | } | ||
375 | |||
376 | #endif /* #ifndef __WUSB_H__ */ | ||
diff --git a/include/linux/uwb.h b/include/linux/uwb.h new file mode 100644 index 000000000000..f9ccbd9a2ced --- /dev/null +++ b/include/linux/uwb.h | |||
@@ -0,0 +1,765 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * UWB API | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: doc: overview of the API, different parts and pointers | ||
24 | */ | ||
25 | |||
26 | #ifndef __LINUX__UWB_H__ | ||
27 | #define __LINUX__UWB_H__ | ||
28 | |||
29 | #include <linux/limits.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/timer.h> | ||
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/uwb/spec.h> | ||
35 | |||
36 | struct uwb_dev; | ||
37 | struct uwb_beca_e; | ||
38 | struct uwb_rc; | ||
39 | struct uwb_rsv; | ||
40 | struct uwb_dbg; | ||
41 | |||
42 | /** | ||
43 | * struct uwb_dev - a UWB Device | ||
44 | * @rc: UWB Radio Controller that discovered the device (kind of its | ||
45 | * parent). | ||
46 | * @bce: a beacon cache entry for this device; or NULL if the device | ||
47 | * is a local radio controller. | ||
48 | * @mac_addr: the EUI-48 address of this device. | ||
49 | * @dev_addr: the current DevAddr used by this device. | ||
50 | * @beacon_slot: the slot number the beacon is using. | ||
51 | * @streams: bitmap of streams allocated to reservations targeted at | ||
52 | * this device. For an RC, this is the streams allocated for | ||
53 | * reservations targeted at DevAddrs. | ||
54 | * | ||
55 | * A UWB device may either by a neighbor or part of a local radio | ||
56 | * controller. | ||
57 | */ | ||
58 | struct uwb_dev { | ||
59 | struct mutex mutex; | ||
60 | struct list_head list_node; | ||
61 | struct device dev; | ||
62 | struct uwb_rc *rc; /* radio controller */ | ||
63 | struct uwb_beca_e *bce; /* Beacon Cache Entry */ | ||
64 | |||
65 | struct uwb_mac_addr mac_addr; | ||
66 | struct uwb_dev_addr dev_addr; | ||
67 | int beacon_slot; | ||
68 | DECLARE_BITMAP(streams, UWB_NUM_STREAMS); | ||
69 | }; | ||
70 | #define to_uwb_dev(d) container_of(d, struct uwb_dev, dev) | ||
71 | |||
72 | /** | ||
73 | * UWB HWA/WHCI Radio Control {Command|Event} Block context IDs | ||
74 | * | ||
75 | * RC[CE]Bs have a 'context ID' field that matches the command with | ||
76 | * the event received to confirm it. | ||
77 | * | ||
78 | * Maximum number of context IDs | ||
79 | */ | ||
80 | enum { UWB_RC_CTX_MAX = 256 }; | ||
81 | |||
82 | |||
83 | /** Notification chain head for UWB generated events to listeners */ | ||
84 | struct uwb_notifs_chain { | ||
85 | struct list_head list; | ||
86 | struct mutex mutex; | ||
87 | }; | ||
88 | |||
89 | /** | ||
90 | * struct uwb_mas_bm - a bitmap of all MAS in a superframe | ||
91 | * @bm: a bitmap of length #UWB_NUM_MAS | ||
92 | */ | ||
93 | struct uwb_mas_bm { | ||
94 | DECLARE_BITMAP(bm, UWB_NUM_MAS); | ||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * uwb_rsv_state - UWB Reservation state. | ||
99 | * | ||
100 | * NONE - reservation is not active (no DRP IE being transmitted). | ||
101 | * | ||
102 | * Owner reservation states: | ||
103 | * | ||
104 | * INITIATED - owner has sent an initial DRP request. | ||
105 | * PENDING - target responded with pending Reason Code. | ||
106 | * MODIFIED - reservation manager is modifying an established | ||
107 | * reservation with a different MAS allocation. | ||
108 | * ESTABLISHED - the reservation has been successfully negotiated. | ||
109 | * | ||
110 | * Target reservation states: | ||
111 | * | ||
112 | * DENIED - request is denied. | ||
113 | * ACCEPTED - request is accepted. | ||
114 | * PENDING - PAL has yet to make a decision to whether to accept or | ||
115 | * deny. | ||
116 | * | ||
117 | * FIXME: further target states TBD. | ||
118 | */ | ||
119 | enum uwb_rsv_state { | ||
120 | UWB_RSV_STATE_NONE, | ||
121 | UWB_RSV_STATE_O_INITIATED, | ||
122 | UWB_RSV_STATE_O_PENDING, | ||
123 | UWB_RSV_STATE_O_MODIFIED, | ||
124 | UWB_RSV_STATE_O_ESTABLISHED, | ||
125 | UWB_RSV_STATE_T_ACCEPTED, | ||
126 | UWB_RSV_STATE_T_DENIED, | ||
127 | UWB_RSV_STATE_T_PENDING, | ||
128 | |||
129 | UWB_RSV_STATE_LAST, | ||
130 | }; | ||
131 | |||
132 | enum uwb_rsv_target_type { | ||
133 | UWB_RSV_TARGET_DEV, | ||
134 | UWB_RSV_TARGET_DEVADDR, | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * struct uwb_rsv_target - the target of a reservation. | ||
139 | * | ||
140 | * Reservations unicast and targeted at a single device | ||
141 | * (UWB_RSV_TARGET_DEV); or (e.g., in the case of WUSB) targeted at a | ||
142 | * specific (private) DevAddr (UWB_RSV_TARGET_DEVADDR). | ||
143 | */ | ||
144 | struct uwb_rsv_target { | ||
145 | enum uwb_rsv_target_type type; | ||
146 | union { | ||
147 | struct uwb_dev *dev; | ||
148 | struct uwb_dev_addr devaddr; | ||
149 | }; | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * Number of streams reserved for reservations targeted at DevAddrs. | ||
154 | */ | ||
155 | #define UWB_NUM_GLOBAL_STREAMS 1 | ||
156 | |||
157 | typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv); | ||
158 | |||
159 | /** | ||
160 | * struct uwb_rsv - a DRP reservation | ||
161 | * | ||
162 | * Data structure management: | ||
163 | * | ||
164 | * @rc: the radio controller this reservation is for | ||
165 | * (as target or owner) | ||
166 | * @rc_node: a list node for the RC | ||
167 | * @pal_node: a list node for the PAL | ||
168 | * | ||
169 | * Owner and target parameters: | ||
170 | * | ||
171 | * @owner: the UWB device owning this reservation | ||
172 | * @target: the target UWB device | ||
173 | * @type: reservation type | ||
174 | * | ||
175 | * Owner parameters: | ||
176 | * | ||
177 | * @max_mas: maxiumum number of MAS | ||
178 | * @min_mas: minimum number of MAS | ||
179 | * @sparsity: owner selected sparsity | ||
180 | * @is_multicast: true iff multicast | ||
181 | * | ||
182 | * @callback: callback function when the reservation completes | ||
183 | * @pal_priv: private data for the PAL making the reservation | ||
184 | * | ||
185 | * Reservation status: | ||
186 | * | ||
187 | * @status: negotiation status | ||
188 | * @stream: stream index allocated for this reservation | ||
189 | * @mas: reserved MAS | ||
190 | * @drp_ie: the DRP IE | ||
191 | * @ie_valid: true iff the DRP IE matches the reservation parameters | ||
192 | * | ||
193 | * DRP reservations are uniquely identified by the owner, target and | ||
194 | * stream index. However, when using a DevAddr as a target (e.g., for | ||
195 | * a WUSB cluster reservation) the responses may be received from | ||
196 | * devices with different DevAddrs. In this case, reservations are | ||
197 | * uniquely identified by just the stream index. A number of stream | ||
198 | * indexes (UWB_NUM_GLOBAL_STREAMS) are reserved for this. | ||
199 | */ | ||
200 | struct uwb_rsv { | ||
201 | struct uwb_rc *rc; | ||
202 | struct list_head rc_node; | ||
203 | struct list_head pal_node; | ||
204 | |||
205 | struct uwb_dev *owner; | ||
206 | struct uwb_rsv_target target; | ||
207 | enum uwb_drp_type type; | ||
208 | int max_mas; | ||
209 | int min_mas; | ||
210 | int sparsity; | ||
211 | bool is_multicast; | ||
212 | |||
213 | uwb_rsv_cb_f callback; | ||
214 | void *pal_priv; | ||
215 | |||
216 | enum uwb_rsv_state state; | ||
217 | u8 stream; | ||
218 | struct uwb_mas_bm mas; | ||
219 | struct uwb_ie_drp *drp_ie; | ||
220 | bool ie_valid; | ||
221 | struct timer_list timer; | ||
222 | bool expired; | ||
223 | }; | ||
224 | |||
225 | static const | ||
226 | struct uwb_mas_bm uwb_mas_bm_zero = { .bm = { 0 } }; | ||
227 | |||
228 | static inline void uwb_mas_bm_copy_le(void *dst, const struct uwb_mas_bm *mas) | ||
229 | { | ||
230 | bitmap_copy_le(dst, mas->bm, UWB_NUM_MAS); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * struct uwb_drp_avail - a radio controller's view of MAS usage | ||
235 | * @global: MAS unused by neighbors (excluding reservations targetted | ||
236 | * or owned by the local radio controller) or the beaon period | ||
237 | * @local: MAS unused by local established reservations | ||
238 | * @pending: MAS unused by local pending reservations | ||
239 | * @ie: DRP Availability IE to be included in the beacon | ||
240 | * @ie_valid: true iff @ie is valid and does not need to regenerated from | ||
241 | * @global and @local | ||
242 | * | ||
243 | * Each radio controller maintains a view of MAS usage or | ||
244 | * availability. MAS available for a new reservation are determined | ||
245 | * from the intersection of @global, @local, and @pending. | ||
246 | * | ||
247 | * The radio controller must transmit a DRP Availability IE that's the | ||
248 | * intersection of @global and @local. | ||
249 | * | ||
250 | * A set bit indicates the MAS is unused and available. | ||
251 | * | ||
252 | * rc->rsvs_mutex should be held before accessing this data structure. | ||
253 | * | ||
254 | * [ECMA-368] section 17.4.3. | ||
255 | */ | ||
256 | struct uwb_drp_avail { | ||
257 | DECLARE_BITMAP(global, UWB_NUM_MAS); | ||
258 | DECLARE_BITMAP(local, UWB_NUM_MAS); | ||
259 | DECLARE_BITMAP(pending, UWB_NUM_MAS); | ||
260 | struct uwb_ie_drp_avail ie; | ||
261 | bool ie_valid; | ||
262 | }; | ||
263 | |||
264 | |||
265 | const char *uwb_rsv_state_str(enum uwb_rsv_state state); | ||
266 | const char *uwb_rsv_type_str(enum uwb_drp_type type); | ||
267 | |||
268 | struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, | ||
269 | void *pal_priv); | ||
270 | void uwb_rsv_destroy(struct uwb_rsv *rsv); | ||
271 | |||
272 | int uwb_rsv_establish(struct uwb_rsv *rsv); | ||
273 | int uwb_rsv_modify(struct uwb_rsv *rsv, | ||
274 | int max_mas, int min_mas, int sparsity); | ||
275 | void uwb_rsv_terminate(struct uwb_rsv *rsv); | ||
276 | |||
277 | void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv); | ||
278 | |||
279 | /** | ||
280 | * Radio Control Interface instance | ||
281 | * | ||
282 | * | ||
283 | * Life cycle rules: those of the UWB Device. | ||
284 | * | ||
285 | * @index: an index number for this radio controller, as used in the | ||
286 | * device name. | ||
287 | * @version: version of protocol supported by this device | ||
288 | * @priv: Backend implementation; rw with uwb_dev.dev.sem taken. | ||
289 | * @cmd: Backend implementation to execute commands; rw and call | ||
290 | * only with uwb_dev.dev.sem taken. | ||
291 | * @reset: Hardware reset of radio controller and any PAL controllers. | ||
292 | * @filter: Backend implementation to manipulate data to and from device | ||
293 | * to be compliant to specification assumed by driver (WHCI | ||
294 | * 0.95). | ||
295 | * | ||
296 | * uwb_dev.dev.mutex is used to execute commands and update | ||
297 | * the corresponding structures; can't use a spinlock | ||
298 | * because rc->cmd() can sleep. | ||
299 | * @ies: This is a dynamically allocated array cacheing the | ||
300 | * IEs (settable by the host) that the beacon of this | ||
301 | * radio controller is currently sending. | ||
302 | * | ||
303 | * In reality, we store here the full command we set to | ||
304 | * the radio controller (which is basically a command | ||
305 | * prefix followed by all the IEs the beacon currently | ||
306 | * contains). This way we don't have to realloc and | ||
307 | * memcpy when setting it. | ||
308 | * | ||
309 | * We set this up in uwb_rc_ie_setup(), where we alloc | ||
310 | * this struct, call get_ie() [so we know which IEs are | ||
311 | * currently being sent, if any]. | ||
312 | * | ||
313 | * @ies_capacity:Amount of space (in bytes) allocated in @ies. The | ||
314 | * amount used is given by sizeof(*ies) plus ies->wIELength | ||
315 | * (which is a little endian quantity all the time). | ||
316 | * @ies_mutex: protect the IE cache | ||
317 | * @dbg: information for the debug interface | ||
318 | */ | ||
319 | struct uwb_rc { | ||
320 | struct uwb_dev uwb_dev; | ||
321 | int index; | ||
322 | u16 version; | ||
323 | |||
324 | struct module *owner; | ||
325 | void *priv; | ||
326 | int (*start)(struct uwb_rc *rc); | ||
327 | void (*stop)(struct uwb_rc *rc); | ||
328 | int (*cmd)(struct uwb_rc *, const struct uwb_rccb *, size_t); | ||
329 | int (*reset)(struct uwb_rc *rc); | ||
330 | int (*filter_cmd)(struct uwb_rc *, struct uwb_rccb **, size_t *); | ||
331 | int (*filter_event)(struct uwb_rc *, struct uwb_rceb **, const size_t, | ||
332 | size_t *, size_t *); | ||
333 | |||
334 | spinlock_t neh_lock; /* protects neh_* and ctx_* */ | ||
335 | struct list_head neh_list; /* Open NE handles */ | ||
336 | unsigned long ctx_bm[UWB_RC_CTX_MAX / 8 / sizeof(unsigned long)]; | ||
337 | u8 ctx_roll; | ||
338 | |||
339 | int beaconing; /* Beaconing state [channel number] */ | ||
340 | int scanning; | ||
341 | enum uwb_scan_type scan_type:3; | ||
342 | unsigned ready:1; | ||
343 | struct uwb_notifs_chain notifs_chain; | ||
344 | |||
345 | struct uwb_drp_avail drp_avail; | ||
346 | struct list_head reservations; | ||
347 | struct mutex rsvs_mutex; | ||
348 | struct workqueue_struct *rsv_workq; | ||
349 | struct work_struct rsv_update_work; | ||
350 | |||
351 | struct mutex ies_mutex; | ||
352 | struct uwb_rc_cmd_set_ie *ies; | ||
353 | size_t ies_capacity; | ||
354 | |||
355 | spinlock_t pal_lock; | ||
356 | struct list_head pals; | ||
357 | |||
358 | struct uwb_dbg *dbg; | ||
359 | }; | ||
360 | |||
361 | |||
362 | /** | ||
363 | * struct uwb_pal - a UWB PAL | ||
364 | * @name: descriptive name for this PAL (wushc, wlp, etc.). | ||
365 | * @device: a device for the PAL. Used to link the PAL and the radio | ||
366 | * controller in sysfs. | ||
367 | * @new_rsv: called when a peer requests a reservation (may be NULL if | ||
368 | * the PAL cannot accept reservation requests). | ||
369 | * | ||
370 | * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB | ||
371 | * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP). | ||
372 | * | ||
373 | * The PALs using a radio controller must register themselves to | ||
374 | * permit the UWB stack to coordinate usage of the radio between the | ||
375 | * various PALs or to allow PALs to response to certain requests from | ||
376 | * peers. | ||
377 | * | ||
378 | * A struct uwb_pal should be embedded in a containing structure | ||
379 | * belonging to the PAL and initialized with uwb_pal_init()). Fields | ||
380 | * should be set appropriately by the PAL before registering the PAL | ||
381 | * with uwb_pal_register(). | ||
382 | */ | ||
383 | struct uwb_pal { | ||
384 | struct list_head node; | ||
385 | const char *name; | ||
386 | struct device *device; | ||
387 | void (*new_rsv)(struct uwb_rsv *rsv); | ||
388 | }; | ||
389 | |||
390 | void uwb_pal_init(struct uwb_pal *pal); | ||
391 | int uwb_pal_register(struct uwb_rc *rc, struct uwb_pal *pal); | ||
392 | void uwb_pal_unregister(struct uwb_rc *rc, struct uwb_pal *pal); | ||
393 | |||
394 | /* | ||
395 | * General public API | ||
396 | * | ||
397 | * This API can be used by UWB device drivers or by those implementing | ||
398 | * UWB Radio Controllers | ||
399 | */ | ||
400 | struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, | ||
401 | const struct uwb_dev_addr *devaddr); | ||
402 | struct uwb_dev *uwb_dev_get_by_rc(struct uwb_dev *, struct uwb_rc *); | ||
403 | static inline void uwb_dev_get(struct uwb_dev *uwb_dev) | ||
404 | { | ||
405 | get_device(&uwb_dev->dev); | ||
406 | } | ||
407 | static inline void uwb_dev_put(struct uwb_dev *uwb_dev) | ||
408 | { | ||
409 | put_device(&uwb_dev->dev); | ||
410 | } | ||
411 | struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev); | ||
412 | |||
413 | /** | ||
414 | * Callback function for 'uwb_{dev,rc}_foreach()'. | ||
415 | * | ||
416 | * @dev: Linux device instance | ||
417 | * 'uwb_dev = container_of(dev, struct uwb_dev, dev)' | ||
418 | * @priv: Data passed by the caller to 'uwb_{dev,rc}_foreach()'. | ||
419 | * | ||
420 | * @returns: 0 to continue the iterations, any other val to stop | ||
421 | * iterating and return the value to the caller of | ||
422 | * _foreach(). | ||
423 | */ | ||
424 | typedef int (*uwb_dev_for_each_f)(struct device *dev, void *priv); | ||
425 | int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f func, void *priv); | ||
426 | |||
427 | struct uwb_rc *uwb_rc_alloc(void); | ||
428 | struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *); | ||
429 | struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *); | ||
430 | void uwb_rc_put(struct uwb_rc *rc); | ||
431 | |||
432 | typedef void (*uwb_rc_cmd_cb_f)(struct uwb_rc *rc, void *arg, | ||
433 | struct uwb_rceb *reply, ssize_t reply_size); | ||
434 | |||
435 | int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name, | ||
436 | struct uwb_rccb *cmd, size_t cmd_size, | ||
437 | u8 expected_type, u16 expected_event, | ||
438 | uwb_rc_cmd_cb_f cb, void *arg); | ||
439 | ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name, | ||
440 | struct uwb_rccb *cmd, size_t cmd_size, | ||
441 | struct uwb_rceb *reply, size_t reply_size); | ||
442 | ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name, | ||
443 | struct uwb_rccb *cmd, size_t cmd_size, | ||
444 | u8 expected_type, u16 expected_event, | ||
445 | struct uwb_rceb **preply); | ||
446 | ssize_t uwb_rc_get_ie(struct uwb_rc *, struct uwb_rc_evt_get_ie **); | ||
447 | int uwb_bg_joined(struct uwb_rc *rc); | ||
448 | |||
449 | size_t __uwb_addr_print(char *, size_t, const unsigned char *, int); | ||
450 | |||
451 | int uwb_rc_dev_addr_set(struct uwb_rc *, const struct uwb_dev_addr *); | ||
452 | int uwb_rc_dev_addr_get(struct uwb_rc *, struct uwb_dev_addr *); | ||
453 | int uwb_rc_mac_addr_set(struct uwb_rc *, const struct uwb_mac_addr *); | ||
454 | int uwb_rc_mac_addr_get(struct uwb_rc *, struct uwb_mac_addr *); | ||
455 | int __uwb_mac_addr_assigned_check(struct device *, void *); | ||
456 | int __uwb_dev_addr_assigned_check(struct device *, void *); | ||
457 | |||
458 | /* Print in @buf a pretty repr of @addr */ | ||
459 | static inline size_t uwb_dev_addr_print(char *buf, size_t buf_size, | ||
460 | const struct uwb_dev_addr *addr) | ||
461 | { | ||
462 | return __uwb_addr_print(buf, buf_size, addr->data, 0); | ||
463 | } | ||
464 | |||
465 | /* Print in @buf a pretty repr of @addr */ | ||
466 | static inline size_t uwb_mac_addr_print(char *buf, size_t buf_size, | ||
467 | const struct uwb_mac_addr *addr) | ||
468 | { | ||
469 | return __uwb_addr_print(buf, buf_size, addr->data, 1); | ||
470 | } | ||
471 | |||
472 | /* @returns 0 if device addresses @addr2 and @addr1 are equal */ | ||
473 | static inline int uwb_dev_addr_cmp(const struct uwb_dev_addr *addr1, | ||
474 | const struct uwb_dev_addr *addr2) | ||
475 | { | ||
476 | return memcmp(addr1, addr2, sizeof(*addr1)); | ||
477 | } | ||
478 | |||
479 | /* @returns 0 if MAC addresses @addr2 and @addr1 are equal */ | ||
480 | static inline int uwb_mac_addr_cmp(const struct uwb_mac_addr *addr1, | ||
481 | const struct uwb_mac_addr *addr2) | ||
482 | { | ||
483 | return memcmp(addr1, addr2, sizeof(*addr1)); | ||
484 | } | ||
485 | |||
486 | /* @returns !0 if a MAC @addr is a broadcast address */ | ||
487 | static inline int uwb_mac_addr_bcast(const struct uwb_mac_addr *addr) | ||
488 | { | ||
489 | struct uwb_mac_addr bcast = { | ||
490 | .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } | ||
491 | }; | ||
492 | return !uwb_mac_addr_cmp(addr, &bcast); | ||
493 | } | ||
494 | |||
495 | /* @returns !0 if a MAC @addr is all zeroes*/ | ||
496 | static inline int uwb_mac_addr_unset(const struct uwb_mac_addr *addr) | ||
497 | { | ||
498 | struct uwb_mac_addr unset = { | ||
499 | .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } | ||
500 | }; | ||
501 | return !uwb_mac_addr_cmp(addr, &unset); | ||
502 | } | ||
503 | |||
504 | /* @returns !0 if the address is in use. */ | ||
505 | static inline unsigned __uwb_dev_addr_assigned(struct uwb_rc *rc, | ||
506 | struct uwb_dev_addr *addr) | ||
507 | { | ||
508 | return uwb_dev_for_each(rc, __uwb_dev_addr_assigned_check, addr); | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * UWB Radio Controller API | ||
513 | * | ||
514 | * This API is used (in addition to the general API) to implement UWB | ||
515 | * Radio Controllers. | ||
516 | */ | ||
517 | void uwb_rc_init(struct uwb_rc *); | ||
518 | int uwb_rc_add(struct uwb_rc *, struct device *dev, void *rc_priv); | ||
519 | void uwb_rc_rm(struct uwb_rc *); | ||
520 | void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t); | ||
521 | void uwb_rc_neh_error(struct uwb_rc *, int); | ||
522 | void uwb_rc_reset_all(struct uwb_rc *rc); | ||
523 | |||
524 | /** | ||
525 | * uwb_rsv_is_owner - is the owner of this reservation the RC? | ||
526 | * @rsv: the reservation | ||
527 | */ | ||
528 | static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv) | ||
529 | { | ||
530 | return rsv->owner == &rsv->rc->uwb_dev; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * Events generated by UWB that can be passed to any listeners | ||
535 | * | ||
536 | * Higher layers can register callback functions with the radio | ||
537 | * controller using uwb_notifs_register(). The radio controller | ||
538 | * maintains a list of all registered handlers and will notify all | ||
539 | * nodes when an event occurs. | ||
540 | */ | ||
541 | enum uwb_notifs { | ||
542 | UWB_NOTIF_BG_JOIN = 0, /* radio controller joined a beacon group */ | ||
543 | UWB_NOTIF_BG_LEAVE = 1, /* radio controller left a beacon group */ | ||
544 | UWB_NOTIF_ONAIR, | ||
545 | UWB_NOTIF_OFFAIR, | ||
546 | }; | ||
547 | |||
548 | /* Callback function registered with UWB */ | ||
549 | struct uwb_notifs_handler { | ||
550 | struct list_head list_node; | ||
551 | void (*cb)(void *, struct uwb_dev *, enum uwb_notifs); | ||
552 | void *data; | ||
553 | }; | ||
554 | |||
555 | int uwb_notifs_register(struct uwb_rc *, struct uwb_notifs_handler *); | ||
556 | int uwb_notifs_deregister(struct uwb_rc *, struct uwb_notifs_handler *); | ||
557 | |||
558 | |||
559 | /** | ||
560 | * UWB radio controller Event Size Entry (for creating entry tables) | ||
561 | * | ||
562 | * WUSB and WHCI define events and notifications, and they might have | ||
563 | * fixed or variable size. | ||
564 | * | ||
565 | * Each event/notification has a size which is not necessarily known | ||
566 | * in advance based on the event code. As well, vendor specific | ||
567 | * events/notifications will have a size impossible to determine | ||
568 | * unless we know about the device's specific details. | ||
569 | * | ||
570 | * It was way too smart of the spec writers not to think that it would | ||
571 | * be impossible for a generic driver to skip over vendor specific | ||
572 | * events/notifications if there are no LENGTH fields in the HEADER of | ||
573 | * each message...the transaction size cannot be counted on as the | ||
574 | * spec does not forbid to pack more than one event in a single | ||
575 | * transaction. | ||
576 | * | ||
577 | * Thus, we guess sizes with tables (or for events, when you know the | ||
578 | * size ahead of time you can use uwb_rc_neh_extra_size*()). We | ||
579 | * register tables with the known events and their sizes, and then we | ||
580 | * traverse those tables. For those with variable length, we provide a | ||
581 | * way to lookup the size inside the event/notification's | ||
582 | * payload. This allows device-specific event size tables to be | ||
583 | * registered. | ||
584 | * | ||
585 | * @size: Size of the payload | ||
586 | * | ||
587 | * @offset: if != 0, at offset @offset-1 starts a field with a length | ||
588 | * that has to be added to @size. The format of the field is | ||
589 | * given by @type. | ||
590 | * | ||
591 | * @type: Type and length of the offset field. Most common is LE 16 | ||
592 | * bits (that's why that is zero); others are there mostly to | ||
593 | * cover for bugs and weirdos. | ||
594 | */ | ||
595 | struct uwb_est_entry { | ||
596 | size_t size; | ||
597 | unsigned offset; | ||
598 | enum { UWB_EST_16 = 0, UWB_EST_8 = 1 } type; | ||
599 | }; | ||
600 | |||
601 | int uwb_est_register(u8 type, u8 code_high, u16 vendor, u16 product, | ||
602 | const struct uwb_est_entry *, size_t entries); | ||
603 | int uwb_est_unregister(u8 type, u8 code_high, u16 vendor, u16 product, | ||
604 | const struct uwb_est_entry *, size_t entries); | ||
605 | ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, | ||
606 | size_t len); | ||
607 | |||
608 | /* -- Misc */ | ||
609 | |||
610 | enum { | ||
611 | EDC_MAX_ERRORS = 10, | ||
612 | EDC_ERROR_TIMEFRAME = HZ, | ||
613 | }; | ||
614 | |||
615 | /* error density counter */ | ||
616 | struct edc { | ||
617 | unsigned long timestart; | ||
618 | u16 errorcount; | ||
619 | }; | ||
620 | |||
621 | static inline | ||
622 | void edc_init(struct edc *edc) | ||
623 | { | ||
624 | edc->timestart = jiffies; | ||
625 | } | ||
626 | |||
627 | /* Called when an error occured. | ||
628 | * This is way to determine if the number of acceptable errors per time | ||
629 | * period has been exceeded. It is not accurate as there are cases in which | ||
630 | * this scheme will not work, for example if there are periodic occurences | ||
631 | * of errors that straddle updates to the start time. This scheme is | ||
632 | * sufficient for our usage. | ||
633 | * | ||
634 | * @returns 1 if maximum acceptable errors per timeframe has been exceeded. | ||
635 | */ | ||
636 | static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe) | ||
637 | { | ||
638 | unsigned long now; | ||
639 | |||
640 | now = jiffies; | ||
641 | if (now - err_hist->timestart > timeframe) { | ||
642 | err_hist->errorcount = 1; | ||
643 | err_hist->timestart = now; | ||
644 | } else if (++err_hist->errorcount > max_err) { | ||
645 | err_hist->errorcount = 0; | ||
646 | err_hist->timestart = now; | ||
647 | return 1; | ||
648 | } | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | |||
653 | /* Information Element handling */ | ||
654 | |||
655 | /* For representing the state of writing to a buffer when iterating */ | ||
656 | struct uwb_buf_ctx { | ||
657 | char *buf; | ||
658 | size_t bytes, size; | ||
659 | }; | ||
660 | |||
661 | typedef int (*uwb_ie_f)(struct uwb_dev *, const struct uwb_ie_hdr *, | ||
662 | size_t, void *); | ||
663 | struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len); | ||
664 | ssize_t uwb_ie_for_each(struct uwb_dev *uwb_dev, uwb_ie_f fn, void *data, | ||
665 | const void *buf, size_t size); | ||
666 | int uwb_ie_dump_hex(struct uwb_dev *, const struct uwb_ie_hdr *, | ||
667 | size_t, void *); | ||
668 | int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *); | ||
669 | struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len); | ||
670 | |||
671 | |||
672 | /* | ||
673 | * Transmission statistics | ||
674 | * | ||
675 | * UWB uses LQI and RSSI (one byte values) for reporting radio signal | ||
676 | * strength and line quality indication. We do quick and dirty | ||
677 | * averages of those. They are signed values, btw. | ||
678 | * | ||
679 | * For 8 bit quantities, we keep the min, the max, an accumulator | ||
680 | * (@sigma) and a # of samples. When @samples gets to 255, we compute | ||
681 | * the average (@sigma / @samples), place it in @sigma and reset | ||
682 | * @samples to 1 (so we use it as the first sample). | ||
683 | * | ||
684 | * Now, statistically speaking, probably I am kicking the kidneys of | ||
685 | * some books I have in my shelves collecting dust, but I just want to | ||
686 | * get an approx, not the Nobel. | ||
687 | * | ||
688 | * LOCKING: there is no locking per se, but we try to keep a lockless | ||
689 | * schema. Only _add_samples() modifies the values--as long as you | ||
690 | * have other locking on top that makes sure that no two calls of | ||
691 | * _add_sample() happen at the same time, then we are fine. Now, for | ||
692 | * resetting the values we just set @samples to 0 and that makes the | ||
693 | * next _add_sample() to start with defaults. Reading the values in | ||
694 | * _show() currently can race, so you need to make sure the calls are | ||
695 | * under the same lock that protects calls to _add_sample(). FIXME: | ||
696 | * currently unlocked (It is not ultraprecise but does the trick. Bite | ||
697 | * me). | ||
698 | */ | ||
699 | struct stats { | ||
700 | s8 min, max; | ||
701 | s16 sigma; | ||
702 | atomic_t samples; | ||
703 | }; | ||
704 | |||
705 | static inline | ||
706 | void stats_init(struct stats *stats) | ||
707 | { | ||
708 | atomic_set(&stats->samples, 0); | ||
709 | wmb(); | ||
710 | } | ||
711 | |||
712 | static inline | ||
713 | void stats_add_sample(struct stats *stats, s8 sample) | ||
714 | { | ||
715 | s8 min, max; | ||
716 | s16 sigma; | ||
717 | unsigned samples = atomic_read(&stats->samples); | ||
718 | if (samples == 0) { /* it was zero before, so we initialize */ | ||
719 | min = 127; | ||
720 | max = -128; | ||
721 | sigma = 0; | ||
722 | } else { | ||
723 | min = stats->min; | ||
724 | max = stats->max; | ||
725 | sigma = stats->sigma; | ||
726 | } | ||
727 | |||
728 | if (sample < min) /* compute new values */ | ||
729 | min = sample; | ||
730 | else if (sample > max) | ||
731 | max = sample; | ||
732 | sigma += sample; | ||
733 | |||
734 | stats->min = min; /* commit */ | ||
735 | stats->max = max; | ||
736 | stats->sigma = sigma; | ||
737 | if (atomic_add_return(1, &stats->samples) > 255) { | ||
738 | /* wrapped around! reset */ | ||
739 | stats->sigma = sigma / 256; | ||
740 | atomic_set(&stats->samples, 1); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static inline ssize_t stats_show(struct stats *stats, char *buf) | ||
745 | { | ||
746 | int min, max, avg; | ||
747 | int samples = atomic_read(&stats->samples); | ||
748 | if (samples == 0) | ||
749 | min = max = avg = 0; | ||
750 | else { | ||
751 | min = stats->min; | ||
752 | max = stats->max; | ||
753 | avg = stats->sigma / samples; | ||
754 | } | ||
755 | return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", min, max, avg); | ||
756 | } | ||
757 | |||
758 | static inline ssize_t stats_store(struct stats *stats, const char *buf, | ||
759 | size_t size) | ||
760 | { | ||
761 | stats_init(stats); | ||
762 | return size; | ||
763 | } | ||
764 | |||
765 | #endif /* #ifndef __LINUX__UWB_H__ */ | ||
diff --git a/include/linux/uwb/debug-cmd.h b/include/linux/uwb/debug-cmd.h new file mode 100644 index 000000000000..1141f41bab5c --- /dev/null +++ b/include/linux/uwb/debug-cmd.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Debug interface commands | ||
4 | * | ||
5 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #ifndef __LINUX__UWB__DEBUG_CMD_H__ | ||
20 | #define __LINUX__UWB__DEBUG_CMD_H__ | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | |||
24 | /* | ||
25 | * Debug interface commands | ||
26 | * | ||
27 | * UWB_DBG_CMD_RSV_ESTABLISH: Establish a new unicast reservation. | ||
28 | * | ||
29 | * UWB_DBG_CMD_RSV_TERMINATE: Terminate the Nth reservation. | ||
30 | */ | ||
31 | |||
32 | enum uwb_dbg_cmd_type { | ||
33 | UWB_DBG_CMD_RSV_ESTABLISH = 1, | ||
34 | UWB_DBG_CMD_RSV_TERMINATE = 2, | ||
35 | }; | ||
36 | |||
37 | struct uwb_dbg_cmd_rsv_establish { | ||
38 | __u8 target[6]; | ||
39 | __u8 type; | ||
40 | __u16 max_mas; | ||
41 | __u16 min_mas; | ||
42 | __u8 sparsity; | ||
43 | }; | ||
44 | |||
45 | struct uwb_dbg_cmd_rsv_terminate { | ||
46 | int index; | ||
47 | }; | ||
48 | |||
49 | struct uwb_dbg_cmd { | ||
50 | __u32 type; | ||
51 | union { | ||
52 | struct uwb_dbg_cmd_rsv_establish rsv_establish; | ||
53 | struct uwb_dbg_cmd_rsv_terminate rsv_terminate; | ||
54 | }; | ||
55 | }; | ||
56 | |||
57 | #endif /* #ifndef __LINUX__UWB__DEBUG_CMD_H__ */ | ||
diff --git a/include/linux/uwb/debug.h b/include/linux/uwb/debug.h new file mode 100644 index 000000000000..a86a73fe303f --- /dev/null +++ b/include/linux/uwb/debug.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Debug Support | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: doc | ||
24 | * Invoke like: | ||
25 | * | ||
26 | * #define D_LOCAL 4 | ||
27 | * #include <linux/uwb/debug.h> | ||
28 | * | ||
29 | * At the end of your include files. | ||
30 | */ | ||
31 | #include <linux/types.h> | ||
32 | |||
33 | struct device; | ||
34 | extern void dump_bytes(struct device *dev, const void *_buf, size_t rsize); | ||
35 | |||
36 | /* Master debug switch; !0 enables, 0 disables */ | ||
37 | #define D_MASTER (!0) | ||
38 | |||
39 | /* Local (per-file) debug switch; #define before #including */ | ||
40 | #ifndef D_LOCAL | ||
41 | #define D_LOCAL 0 | ||
42 | #endif | ||
43 | |||
44 | #undef __d_printf | ||
45 | #undef d_fnstart | ||
46 | #undef d_fnend | ||
47 | #undef d_printf | ||
48 | #undef d_dump | ||
49 | |||
50 | #define __d_printf(l, _tag, _dev, f, a...) \ | ||
51 | do { \ | ||
52 | struct device *__dev = (_dev); \ | ||
53 | if (D_MASTER && D_LOCAL >= (l)) { \ | ||
54 | char __head[64] = ""; \ | ||
55 | if (_dev != NULL) { \ | ||
56 | if ((unsigned long)__dev < 4096) \ | ||
57 | printk(KERN_ERR "E: Corrupt dev %p\n", \ | ||
58 | __dev); \ | ||
59 | else \ | ||
60 | snprintf(__head, sizeof(__head), \ | ||
61 | "%s %s: ", \ | ||
62 | dev_driver_string(__dev), \ | ||
63 | __dev->bus_id); \ | ||
64 | } \ | ||
65 | printk(KERN_ERR "%s%s" _tag ": " f, __head, \ | ||
66 | __func__, ## a); \ | ||
67 | } \ | ||
68 | } while (0 && _dev) | ||
69 | |||
70 | #define d_fnstart(l, _dev, f, a...) \ | ||
71 | __d_printf(l, " FNSTART", _dev, f, ## a) | ||
72 | #define d_fnend(l, _dev, f, a...) \ | ||
73 | __d_printf(l, " FNEND", _dev, f, ## a) | ||
74 | #define d_printf(l, _dev, f, a...) \ | ||
75 | __d_printf(l, "", _dev, f, ## a) | ||
76 | #define d_dump(l, _dev, ptr, size) \ | ||
77 | do { \ | ||
78 | struct device *__dev = _dev; \ | ||
79 | if (D_MASTER && D_LOCAL >= (l)) \ | ||
80 | dump_bytes(__dev, ptr, size); \ | ||
81 | } while (0 && _dev) | ||
82 | #define d_test(l) (D_MASTER && D_LOCAL >= (l)) | ||
diff --git a/include/linux/uwb/spec.h b/include/linux/uwb/spec.h new file mode 100644 index 000000000000..198c15f8e251 --- /dev/null +++ b/include/linux/uwb/spec.h | |||
@@ -0,0 +1,727 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * UWB Standard definitions | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * All these definitions are based on the ECMA-368 standard. | ||
24 | * | ||
25 | * Note all definitions are Little Endian in the wire, and we will | ||
26 | * convert them to host order before operating on the bitfields (that | ||
27 | * yes, we use extensively). | ||
28 | */ | ||
29 | |||
30 | #ifndef __LINUX__UWB_SPEC_H__ | ||
31 | #define __LINUX__UWB_SPEC_H__ | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/bitmap.h> | ||
35 | |||
36 | #define i1480_FW 0x00000303 | ||
37 | /* #define i1480_FW 0x00000302 */ | ||
38 | |||
39 | /** | ||
40 | * Number of Medium Access Slots in a superframe. | ||
41 | * | ||
42 | * UWB divides time in SuperFrames, each one divided in 256 pieces, or | ||
43 | * Medium Access Slots. See MBOA MAC[5.4.5] for details. The MAS is the | ||
44 | * basic bandwidth allocation unit in UWB. | ||
45 | */ | ||
46 | enum { UWB_NUM_MAS = 256 }; | ||
47 | |||
48 | /** | ||
49 | * Number of Zones in superframe. | ||
50 | * | ||
51 | * UWB divides the superframe into zones with numbering starting from BPST. | ||
52 | * See MBOA MAC[16.8.6] | ||
53 | */ | ||
54 | enum { UWB_NUM_ZONES = 16 }; | ||
55 | |||
56 | /* | ||
57 | * Number of MAS in a zone. | ||
58 | */ | ||
59 | #define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES) | ||
60 | |||
61 | /* | ||
62 | * Number of streams per DRP reservation between a pair of devices. | ||
63 | * | ||
64 | * [ECMA-368] section 16.8.6. | ||
65 | */ | ||
66 | enum { UWB_NUM_STREAMS = 8 }; | ||
67 | |||
68 | /* | ||
69 | * mMasLength | ||
70 | * | ||
71 | * The length of a MAS in microseconds. | ||
72 | * | ||
73 | * [ECMA-368] section 17.16. | ||
74 | */ | ||
75 | enum { UWB_MAS_LENGTH_US = 256 }; | ||
76 | |||
77 | /* | ||
78 | * mBeaconSlotLength | ||
79 | * | ||
80 | * The length of the beacon slot in microseconds. | ||
81 | * | ||
82 | * [ECMA-368] section 17.16 | ||
83 | */ | ||
84 | enum { UWB_BEACON_SLOT_LENGTH_US = 85 }; | ||
85 | |||
86 | /* | ||
87 | * mMaxLostBeacons | ||
88 | * | ||
89 | * The number beacons missing in consecutive superframes before a | ||
90 | * device can be considered as unreachable. | ||
91 | * | ||
92 | * [ECMA-368] section 17.16 | ||
93 | */ | ||
94 | enum { UWB_MAX_LOST_BEACONS = 3 }; | ||
95 | |||
96 | /* | ||
97 | * Length of a superframe in microseconds. | ||
98 | */ | ||
99 | #define UWB_SUPERFRAME_LENGTH_US (UWB_MAS_LENGTH_US * UWB_NUM_MAS) | ||
100 | |||
101 | /** | ||
102 | * UWB MAC address | ||
103 | * | ||
104 | * It is *imperative* that this struct is exactly 6 packed bytes (as | ||
105 | * it is also used to define headers sent down and up the wire/radio). | ||
106 | */ | ||
107 | struct uwb_mac_addr { | ||
108 | u8 data[6]; | ||
109 | } __attribute__((packed)); | ||
110 | |||
111 | |||
112 | /** | ||
113 | * UWB device address | ||
114 | * | ||
115 | * It is *imperative* that this struct is exactly 6 packed bytes (as | ||
116 | * it is also used to define headers sent down and up the wire/radio). | ||
117 | */ | ||
118 | struct uwb_dev_addr { | ||
119 | u8 data[2]; | ||
120 | } __attribute__((packed)); | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Types of UWB addresses | ||
125 | * | ||
126 | * Order matters (by size). | ||
127 | */ | ||
128 | enum uwb_addr_type { | ||
129 | UWB_ADDR_DEV = 0, | ||
130 | UWB_ADDR_MAC = 1, | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** Size of a char buffer for printing a MAC/device address */ | ||
135 | enum { UWB_ADDR_STRSIZE = 32 }; | ||
136 | |||
137 | |||
138 | /** UWB WiMedia protocol IDs. */ | ||
139 | enum uwb_prid { | ||
140 | UWB_PRID_WLP_RESERVED = 0x0000, | ||
141 | UWB_PRID_WLP = 0x0001, | ||
142 | UWB_PRID_WUSB_BOT = 0x0010, | ||
143 | UWB_PRID_WUSB = 0x0010, | ||
144 | UWB_PRID_WUSB_TOP = 0x001F, | ||
145 | }; | ||
146 | |||
147 | |||
148 | /** PHY Rate (MBOA MAC[7.8.12, Table 61]) */ | ||
149 | enum uwb_phy_rate { | ||
150 | UWB_PHY_RATE_53 = 0, | ||
151 | UWB_PHY_RATE_80, | ||
152 | UWB_PHY_RATE_106, | ||
153 | UWB_PHY_RATE_160, | ||
154 | UWB_PHY_RATE_200, | ||
155 | UWB_PHY_RATE_320, | ||
156 | UWB_PHY_RATE_400, | ||
157 | UWB_PHY_RATE_480, | ||
158 | UWB_PHY_RATE_INVALID | ||
159 | }; | ||
160 | |||
161 | |||
162 | /** | ||
163 | * Different ways to scan (MBOA MAC[6.2.2, Table 8], WUSB[Table 8-78]) | ||
164 | */ | ||
165 | enum uwb_scan_type { | ||
166 | UWB_SCAN_ONLY = 0, | ||
167 | UWB_SCAN_OUTSIDE_BP, | ||
168 | UWB_SCAN_WHILE_INACTIVE, | ||
169 | UWB_SCAN_DISABLED, | ||
170 | UWB_SCAN_ONLY_STARTTIME, | ||
171 | UWB_SCAN_TOP | ||
172 | }; | ||
173 | |||
174 | |||
175 | /** ACK Policy types (MBOA MAC[7.2.1.3]) */ | ||
176 | enum uwb_ack_pol { | ||
177 | UWB_ACK_NO = 0, | ||
178 | UWB_ACK_INM = 1, | ||
179 | UWB_ACK_B = 2, | ||
180 | UWB_ACK_B_REQ = 3, | ||
181 | }; | ||
182 | |||
183 | |||
184 | /** DRP reservation types ([ECMA-368 table 106) */ | ||
185 | enum uwb_drp_type { | ||
186 | UWB_DRP_TYPE_ALIEN_BP = 0, | ||
187 | UWB_DRP_TYPE_HARD, | ||
188 | UWB_DRP_TYPE_SOFT, | ||
189 | UWB_DRP_TYPE_PRIVATE, | ||
190 | UWB_DRP_TYPE_PCA, | ||
191 | }; | ||
192 | |||
193 | |||
194 | /** DRP Reason Codes ([ECMA-368] table 107) */ | ||
195 | enum uwb_drp_reason { | ||
196 | UWB_DRP_REASON_ACCEPTED = 0, | ||
197 | UWB_DRP_REASON_CONFLICT, | ||
198 | UWB_DRP_REASON_PENDING, | ||
199 | UWB_DRP_REASON_DENIED, | ||
200 | UWB_DRP_REASON_MODIFIED, | ||
201 | }; | ||
202 | |||
203 | /** | ||
204 | * DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9]) | ||
205 | */ | ||
206 | enum uwb_drp_notif_reason { | ||
207 | UWB_DRP_NOTIF_DRP_IE_RCVD = 0, | ||
208 | UWB_DRP_NOTIF_CONFLICT, | ||
209 | UWB_DRP_NOTIF_TERMINATE, | ||
210 | }; | ||
211 | |||
212 | |||
213 | /** Allocation of MAS slots in a DRP request MBOA MAC[7.8.7] */ | ||
214 | struct uwb_drp_alloc { | ||
215 | __le16 zone_bm; | ||
216 | __le16 mas_bm; | ||
217 | } __attribute__((packed)); | ||
218 | |||
219 | |||
220 | /** General MAC Header format (ECMA-368[16.2]) */ | ||
221 | struct uwb_mac_frame_hdr { | ||
222 | __le16 Frame_Control; | ||
223 | struct uwb_dev_addr DestAddr; | ||
224 | struct uwb_dev_addr SrcAddr; | ||
225 | __le16 Sequence_Control; | ||
226 | __le16 Access_Information; | ||
227 | } __attribute__((packed)); | ||
228 | |||
229 | |||
230 | /** | ||
231 | * uwb_beacon_frame - a beacon frame including MAC headers | ||
232 | * | ||
233 | * [ECMA] section 16.3. | ||
234 | */ | ||
235 | struct uwb_beacon_frame { | ||
236 | struct uwb_mac_frame_hdr hdr; | ||
237 | struct uwb_mac_addr Device_Identifier; /* may be a NULL EUI-48 */ | ||
238 | u8 Beacon_Slot_Number; | ||
239 | u8 Device_Control; | ||
240 | u8 IEData[]; | ||
241 | } __attribute__((packed)); | ||
242 | |||
243 | |||
244 | /** Information Element codes (MBOA MAC[T54]) */ | ||
245 | enum uwb_ie { | ||
246 | UWB_PCA_AVAILABILITY = 2, | ||
247 | UWB_IE_DRP_AVAILABILITY = 8, | ||
248 | UWB_IE_DRP = 9, | ||
249 | UWB_BP_SWITCH_IE = 11, | ||
250 | UWB_MAC_CAPABILITIES_IE = 12, | ||
251 | UWB_PHY_CAPABILITIES_IE = 13, | ||
252 | UWB_APP_SPEC_PROBE_IE = 15, | ||
253 | UWB_IDENTIFICATION_IE = 19, | ||
254 | UWB_MASTER_KEY_ID_IE = 20, | ||
255 | UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */ | ||
256 | UWB_APP_SPEC_IE = 255, | ||
257 | }; | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Header common to all Information Elements (IEs) | ||
262 | */ | ||
263 | struct uwb_ie_hdr { | ||
264 | u8 element_id; /* enum uwb_ie */ | ||
265 | u8 length; | ||
266 | } __attribute__((packed)); | ||
267 | |||
268 | |||
269 | /** Dynamic Reservation Protocol IE (MBOA MAC[7.8.6]) */ | ||
270 | struct uwb_ie_drp { | ||
271 | struct uwb_ie_hdr hdr; | ||
272 | __le16 drp_control; | ||
273 | struct uwb_dev_addr dev_addr; | ||
274 | struct uwb_drp_alloc allocs[]; | ||
275 | } __attribute__((packed)); | ||
276 | |||
277 | static inline int uwb_ie_drp_type(struct uwb_ie_drp *ie) | ||
278 | { | ||
279 | return (le16_to_cpu(ie->drp_control) >> 0) & 0x7; | ||
280 | } | ||
281 | |||
282 | static inline int uwb_ie_drp_stream_index(struct uwb_ie_drp *ie) | ||
283 | { | ||
284 | return (le16_to_cpu(ie->drp_control) >> 3) & 0x7; | ||
285 | } | ||
286 | |||
287 | static inline int uwb_ie_drp_reason_code(struct uwb_ie_drp *ie) | ||
288 | { | ||
289 | return (le16_to_cpu(ie->drp_control) >> 6) & 0x7; | ||
290 | } | ||
291 | |||
292 | static inline int uwb_ie_drp_status(struct uwb_ie_drp *ie) | ||
293 | { | ||
294 | return (le16_to_cpu(ie->drp_control) >> 9) & 0x1; | ||
295 | } | ||
296 | |||
297 | static inline int uwb_ie_drp_owner(struct uwb_ie_drp *ie) | ||
298 | { | ||
299 | return (le16_to_cpu(ie->drp_control) >> 10) & 0x1; | ||
300 | } | ||
301 | |||
302 | static inline int uwb_ie_drp_tiebreaker(struct uwb_ie_drp *ie) | ||
303 | { | ||
304 | return (le16_to_cpu(ie->drp_control) >> 11) & 0x1; | ||
305 | } | ||
306 | |||
307 | static inline int uwb_ie_drp_unsafe(struct uwb_ie_drp *ie) | ||
308 | { | ||
309 | return (le16_to_cpu(ie->drp_control) >> 12) & 0x1; | ||
310 | } | ||
311 | |||
312 | static inline void uwb_ie_drp_set_type(struct uwb_ie_drp *ie, enum uwb_drp_type type) | ||
313 | { | ||
314 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
315 | drp_control = (drp_control & ~(0x7 << 0)) | (type << 0); | ||
316 | ie->drp_control = cpu_to_le16(drp_control); | ||
317 | } | ||
318 | |||
319 | static inline void uwb_ie_drp_set_stream_index(struct uwb_ie_drp *ie, int stream_index) | ||
320 | { | ||
321 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
322 | drp_control = (drp_control & ~(0x7 << 3)) | (stream_index << 3); | ||
323 | ie->drp_control = cpu_to_le16(drp_control); | ||
324 | } | ||
325 | |||
326 | static inline void uwb_ie_drp_set_reason_code(struct uwb_ie_drp *ie, | ||
327 | enum uwb_drp_reason reason_code) | ||
328 | { | ||
329 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
330 | drp_control = (ie->drp_control & ~(0x7 << 6)) | (reason_code << 6); | ||
331 | ie->drp_control = cpu_to_le16(drp_control); | ||
332 | } | ||
333 | |||
334 | static inline void uwb_ie_drp_set_status(struct uwb_ie_drp *ie, int status) | ||
335 | { | ||
336 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
337 | drp_control = (drp_control & ~(0x1 << 9)) | (status << 9); | ||
338 | ie->drp_control = cpu_to_le16(drp_control); | ||
339 | } | ||
340 | |||
341 | static inline void uwb_ie_drp_set_owner(struct uwb_ie_drp *ie, int owner) | ||
342 | { | ||
343 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
344 | drp_control = (drp_control & ~(0x1 << 10)) | (owner << 10); | ||
345 | ie->drp_control = cpu_to_le16(drp_control); | ||
346 | } | ||
347 | |||
348 | static inline void uwb_ie_drp_set_tiebreaker(struct uwb_ie_drp *ie, int tiebreaker) | ||
349 | { | ||
350 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
351 | drp_control = (drp_control & ~(0x1 << 11)) | (tiebreaker << 11); | ||
352 | ie->drp_control = cpu_to_le16(drp_control); | ||
353 | } | ||
354 | |||
355 | static inline void uwb_ie_drp_set_unsafe(struct uwb_ie_drp *ie, int unsafe) | ||
356 | { | ||
357 | u16 drp_control = le16_to_cpu(ie->drp_control); | ||
358 | drp_control = (drp_control & ~(0x1 << 12)) | (unsafe << 12); | ||
359 | ie->drp_control = cpu_to_le16(drp_control); | ||
360 | } | ||
361 | |||
362 | /** Dynamic Reservation Protocol IE (MBOA MAC[7.8.7]) */ | ||
363 | struct uwb_ie_drp_avail { | ||
364 | struct uwb_ie_hdr hdr; | ||
365 | DECLARE_BITMAP(bmp, UWB_NUM_MAS); | ||
366 | } __attribute__((packed)); | ||
367 | |||
368 | /** | ||
369 | * The Vendor ID is set to an OUI that indicates the vendor of the device. | ||
370 | * ECMA-368 [16.8.10] | ||
371 | */ | ||
372 | struct uwb_vendor_id { | ||
373 | u8 data[3]; | ||
374 | } __attribute__((packed)); | ||
375 | |||
376 | /** | ||
377 | * The device type ID | ||
378 | * FIXME: clarify what this means | ||
379 | * ECMA-368 [16.8.10] | ||
380 | */ | ||
381 | struct uwb_device_type_id { | ||
382 | u8 data[3]; | ||
383 | } __attribute__((packed)); | ||
384 | |||
385 | |||
386 | /** | ||
387 | * UWB device information types | ||
388 | * ECMA-368 [16.8.10] | ||
389 | */ | ||
390 | enum uwb_dev_info_type { | ||
391 | UWB_DEV_INFO_VENDOR_ID = 0, | ||
392 | UWB_DEV_INFO_VENDOR_TYPE, | ||
393 | UWB_DEV_INFO_NAME, | ||
394 | }; | ||
395 | |||
396 | /** | ||
397 | * UWB device information found in Identification IE | ||
398 | * ECMA-368 [16.8.10] | ||
399 | */ | ||
400 | struct uwb_dev_info { | ||
401 | u8 type; /* enum uwb_dev_info_type */ | ||
402 | u8 length; | ||
403 | u8 data[]; | ||
404 | } __attribute__((packed)); | ||
405 | |||
406 | /** | ||
407 | * UWB Identification IE | ||
408 | * ECMA-368 [16.8.10] | ||
409 | */ | ||
410 | struct uwb_identification_ie { | ||
411 | struct uwb_ie_hdr hdr; | ||
412 | struct uwb_dev_info info[]; | ||
413 | } __attribute__((packed)); | ||
414 | |||
415 | /* | ||
416 | * UWB Radio Controller | ||
417 | * | ||
418 | * These definitions are common to the Radio Control layers as | ||
419 | * exported by the WUSB1.0 HWA and WHCI interfaces. | ||
420 | */ | ||
421 | |||
422 | /** Radio Control Command Block (WUSB1.0[Table 8-65] and WHCI 0.95) */ | ||
423 | struct uwb_rccb { | ||
424 | u8 bCommandType; /* enum hwa_cet */ | ||
425 | __le16 wCommand; /* Command code */ | ||
426 | u8 bCommandContext; /* Context ID */ | ||
427 | } __attribute__((packed)); | ||
428 | |||
429 | |||
430 | /** Radio Control Event Block (WUSB[table 8-66], WHCI 0.95) */ | ||
431 | struct uwb_rceb { | ||
432 | u8 bEventType; /* enum hwa_cet */ | ||
433 | __le16 wEvent; /* Event code */ | ||
434 | u8 bEventContext; /* Context ID */ | ||
435 | } __attribute__((packed)); | ||
436 | |||
437 | |||
438 | enum { | ||
439 | UWB_RC_CET_GENERAL = 0, /* General Command/Event type */ | ||
440 | UWB_RC_CET_EX_TYPE_1 = 1, /* Extended Type 1 Command/Event type */ | ||
441 | }; | ||
442 | |||
443 | /* Commands to the radio controller */ | ||
444 | enum uwb_rc_cmd { | ||
445 | UWB_RC_CMD_CHANNEL_CHANGE = 16, | ||
446 | UWB_RC_CMD_DEV_ADDR_MGMT = 17, /* Device Address Management */ | ||
447 | UWB_RC_CMD_GET_IE = 18, /* GET Information Elements */ | ||
448 | UWB_RC_CMD_RESET = 19, | ||
449 | UWB_RC_CMD_SCAN = 20, /* Scan management */ | ||
450 | UWB_RC_CMD_SET_BEACON_FILTER = 21, | ||
451 | UWB_RC_CMD_SET_DRP_IE = 22, /* Dynamic Reservation Protocol IEs */ | ||
452 | UWB_RC_CMD_SET_IE = 23, /* Information Element management */ | ||
453 | UWB_RC_CMD_SET_NOTIFICATION_FILTER = 24, | ||
454 | UWB_RC_CMD_SET_TX_POWER = 25, | ||
455 | UWB_RC_CMD_SLEEP = 26, | ||
456 | UWB_RC_CMD_START_BEACON = 27, | ||
457 | UWB_RC_CMD_STOP_BEACON = 28, | ||
458 | UWB_RC_CMD_BP_MERGE = 29, | ||
459 | UWB_RC_CMD_SEND_COMMAND_FRAME = 30, | ||
460 | UWB_RC_CMD_SET_ASIE_NOTIF = 31, | ||
461 | }; | ||
462 | |||
463 | /* Notifications from the radio controller */ | ||
464 | enum uwb_rc_evt { | ||
465 | UWB_RC_EVT_IE_RCV = 0, | ||
466 | UWB_RC_EVT_BEACON = 1, | ||
467 | UWB_RC_EVT_BEACON_SIZE = 2, | ||
468 | UWB_RC_EVT_BPOIE_CHANGE = 3, | ||
469 | UWB_RC_EVT_BP_SLOT_CHANGE = 4, | ||
470 | UWB_RC_EVT_BP_SWITCH_IE_RCV = 5, | ||
471 | UWB_RC_EVT_DEV_ADDR_CONFLICT = 6, | ||
472 | UWB_RC_EVT_DRP_AVAIL = 7, | ||
473 | UWB_RC_EVT_DRP = 8, | ||
474 | UWB_RC_EVT_BP_SWITCH_STATUS = 9, | ||
475 | UWB_RC_EVT_CMD_FRAME_RCV = 10, | ||
476 | UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV = 11, | ||
477 | /* Events (command responses) use the same code as the command */ | ||
478 | UWB_RC_EVT_UNKNOWN_CMD_RCV = 65535, | ||
479 | }; | ||
480 | |||
481 | enum uwb_rc_extended_type_1_cmd { | ||
482 | UWB_RC_SET_DAA_ENERGY_MASK = 32, | ||
483 | UWB_RC_SET_NOTIFICATION_FILTER_EX = 33, | ||
484 | }; | ||
485 | |||
486 | enum uwb_rc_extended_type_1_evt { | ||
487 | UWB_RC_DAA_ENERGY_DETECTED = 0, | ||
488 | }; | ||
489 | |||
490 | /* Radio Control Result Code. [WHCI] table 3-3. */ | ||
491 | enum { | ||
492 | UWB_RC_RES_SUCCESS = 0, | ||
493 | UWB_RC_RES_FAIL, | ||
494 | UWB_RC_RES_FAIL_HARDWARE, | ||
495 | UWB_RC_RES_FAIL_NO_SLOTS, | ||
496 | UWB_RC_RES_FAIL_BEACON_TOO_LARGE, | ||
497 | UWB_RC_RES_FAIL_INVALID_PARAMETER, | ||
498 | UWB_RC_RES_FAIL_UNSUPPORTED_PWR_LEVEL, | ||
499 | UWB_RC_RES_FAIL_INVALID_IE_DATA, | ||
500 | UWB_RC_RES_FAIL_BEACON_SIZE_EXCEEDED, | ||
501 | UWB_RC_RES_FAIL_CANCELLED, | ||
502 | UWB_RC_RES_FAIL_INVALID_STATE, | ||
503 | UWB_RC_RES_FAIL_INVALID_SIZE, | ||
504 | UWB_RC_RES_FAIL_ACK_NOT_RECEIVED, | ||
505 | UWB_RC_RES_FAIL_NO_MORE_ASIE_NOTIF, | ||
506 | UWB_RC_RES_FAIL_TIME_OUT = 255, | ||
507 | }; | ||
508 | |||
509 | /* Confirm event. [WHCI] section 3.1.3.1 etc. */ | ||
510 | struct uwb_rc_evt_confirm { | ||
511 | struct uwb_rceb rceb; | ||
512 | u8 bResultCode; | ||
513 | } __attribute__((packed)); | ||
514 | |||
515 | /* Device Address Management event. [WHCI] section 3.1.3.2. */ | ||
516 | struct uwb_rc_evt_dev_addr_mgmt { | ||
517 | struct uwb_rceb rceb; | ||
518 | u8 baAddr[6]; | ||
519 | u8 bResultCode; | ||
520 | } __attribute__((packed)); | ||
521 | |||
522 | |||
523 | /* Get IE Event. [WHCI] section 3.1.3.3. */ | ||
524 | struct uwb_rc_evt_get_ie { | ||
525 | struct uwb_rceb rceb; | ||
526 | __le16 wIELength; | ||
527 | u8 IEData[]; | ||
528 | } __attribute__((packed)); | ||
529 | |||
530 | /* Set DRP IE Event. [WHCI] section 3.1.3.7. */ | ||
531 | struct uwb_rc_evt_set_drp_ie { | ||
532 | struct uwb_rceb rceb; | ||
533 | __le16 wRemainingSpace; | ||
534 | u8 bResultCode; | ||
535 | } __attribute__((packed)); | ||
536 | |||
537 | /* Set IE Event. [WHCI] section 3.1.3.8. */ | ||
538 | struct uwb_rc_evt_set_ie { | ||
539 | struct uwb_rceb rceb; | ||
540 | __le16 RemainingSpace; | ||
541 | u8 bResultCode; | ||
542 | } __attribute__((packed)); | ||
543 | |||
544 | /* Scan command. [WHCI] 3.1.3.5. */ | ||
545 | struct uwb_rc_cmd_scan { | ||
546 | struct uwb_rccb rccb; | ||
547 | u8 bChannelNumber; | ||
548 | u8 bScanState; | ||
549 | __le16 wStartTime; | ||
550 | } __attribute__((packed)); | ||
551 | |||
552 | /* Set DRP IE command. [WHCI] section 3.1.3.7. */ | ||
553 | struct uwb_rc_cmd_set_drp_ie { | ||
554 | struct uwb_rccb rccb; | ||
555 | __le16 wIELength; | ||
556 | struct uwb_ie_drp IEData[]; | ||
557 | } __attribute__((packed)); | ||
558 | |||
559 | /* Set IE command. [WHCI] section 3.1.3.8. */ | ||
560 | struct uwb_rc_cmd_set_ie { | ||
561 | struct uwb_rccb rccb; | ||
562 | __le16 wIELength; | ||
563 | u8 IEData[]; | ||
564 | } __attribute__((packed)); | ||
565 | |||
566 | /* Set DAA Energy Mask event. [WHCI 0.96] section 3.1.3.17. */ | ||
567 | struct uwb_rc_evt_set_daa_energy_mask { | ||
568 | struct uwb_rceb rceb; | ||
569 | __le16 wLength; | ||
570 | u8 result; | ||
571 | } __attribute__((packed)); | ||
572 | |||
573 | /* Set Notification Filter Extended event. [WHCI 0.96] section 3.1.3.18. */ | ||
574 | struct uwb_rc_evt_set_notification_filter_ex { | ||
575 | struct uwb_rceb rceb; | ||
576 | __le16 wLength; | ||
577 | u8 result; | ||
578 | } __attribute__((packed)); | ||
579 | |||
580 | /* IE Received notification. [WHCI] section 3.1.4.1. */ | ||
581 | struct uwb_rc_evt_ie_rcv { | ||
582 | struct uwb_rceb rceb; | ||
583 | struct uwb_dev_addr SrcAddr; | ||
584 | __le16 wIELength; | ||
585 | u8 IEData[]; | ||
586 | } __attribute__((packed)); | ||
587 | |||
588 | /* Type of the received beacon. [WHCI] section 3.1.4.2. */ | ||
589 | enum uwb_rc_beacon_type { | ||
590 | UWB_RC_BEACON_TYPE_SCAN = 0, | ||
591 | UWB_RC_BEACON_TYPE_NEIGHBOR, | ||
592 | UWB_RC_BEACON_TYPE_OL_ALIEN, | ||
593 | UWB_RC_BEACON_TYPE_NOL_ALIEN, | ||
594 | }; | ||
595 | |||
596 | /* Beacon received notification. [WHCI] 3.1.4.2. */ | ||
597 | struct uwb_rc_evt_beacon { | ||
598 | struct uwb_rceb rceb; | ||
599 | u8 bChannelNumber; | ||
600 | u8 bBeaconType; | ||
601 | __le16 wBPSTOffset; | ||
602 | u8 bLQI; | ||
603 | u8 bRSSI; | ||
604 | __le16 wBeaconInfoLength; | ||
605 | u8 BeaconInfo[]; | ||
606 | } __attribute__((packed)); | ||
607 | |||
608 | |||
609 | /* Beacon Size Change notification. [WHCI] section 3.1.4.3 */ | ||
610 | struct uwb_rc_evt_beacon_size { | ||
611 | struct uwb_rceb rceb; | ||
612 | __le16 wNewBeaconSize; | ||
613 | } __attribute__((packed)); | ||
614 | |||
615 | |||
616 | /* BPOIE Change notification. [WHCI] section 3.1.4.4. */ | ||
617 | struct uwb_rc_evt_bpoie_change { | ||
618 | struct uwb_rceb rceb; | ||
619 | __le16 wBPOIELength; | ||
620 | u8 BPOIE[]; | ||
621 | } __attribute__((packed)); | ||
622 | |||
623 | |||
624 | /* Beacon Slot Change notification. [WHCI] section 3.1.4.5. */ | ||
625 | struct uwb_rc_evt_bp_slot_change { | ||
626 | struct uwb_rceb rceb; | ||
627 | u8 slot_info; | ||
628 | } __attribute__((packed)); | ||
629 | |||
630 | static inline int uwb_rc_evt_bp_slot_change_slot_num( | ||
631 | const struct uwb_rc_evt_bp_slot_change *evt) | ||
632 | { | ||
633 | return evt->slot_info & 0x7f; | ||
634 | } | ||
635 | |||
636 | static inline int uwb_rc_evt_bp_slot_change_no_slot( | ||
637 | const struct uwb_rc_evt_bp_slot_change *evt) | ||
638 | { | ||
639 | return (evt->slot_info & 0x80) >> 7; | ||
640 | } | ||
641 | |||
642 | /* BP Switch IE Received notification. [WHCI] section 3.1.4.6. */ | ||
643 | struct uwb_rc_evt_bp_switch_ie_rcv { | ||
644 | struct uwb_rceb rceb; | ||
645 | struct uwb_dev_addr wSrcAddr; | ||
646 | __le16 wIELength; | ||
647 | u8 IEData[]; | ||
648 | } __attribute__((packed)); | ||
649 | |||
650 | /* DevAddr Conflict notification. [WHCI] section 3.1.4.7. */ | ||
651 | struct uwb_rc_evt_dev_addr_conflict { | ||
652 | struct uwb_rceb rceb; | ||
653 | } __attribute__((packed)); | ||
654 | |||
655 | /* DRP notification. [WHCI] section 3.1.4.9. */ | ||
656 | struct uwb_rc_evt_drp { | ||
657 | struct uwb_rceb rceb; | ||
658 | struct uwb_dev_addr src_addr; | ||
659 | u8 reason; | ||
660 | u8 beacon_slot_number; | ||
661 | __le16 ie_length; | ||
662 | u8 ie_data[]; | ||
663 | } __attribute__((packed)); | ||
664 | |||
665 | static inline enum uwb_drp_notif_reason uwb_rc_evt_drp_reason(struct uwb_rc_evt_drp *evt) | ||
666 | { | ||
667 | return evt->reason & 0x0f; | ||
668 | } | ||
669 | |||
670 | |||
671 | /* DRP Availability Change notification. [WHCI] section 3.1.4.8. */ | ||
672 | struct uwb_rc_evt_drp_avail { | ||
673 | struct uwb_rceb rceb; | ||
674 | DECLARE_BITMAP(bmp, UWB_NUM_MAS); | ||
675 | } __attribute__((packed)); | ||
676 | |||
677 | /* BP switch status notification. [WHCI] section 3.1.4.10. */ | ||
678 | struct uwb_rc_evt_bp_switch_status { | ||
679 | struct uwb_rceb rceb; | ||
680 | u8 status; | ||
681 | u8 slot_offset; | ||
682 | __le16 bpst_offset; | ||
683 | u8 move_countdown; | ||
684 | } __attribute__((packed)); | ||
685 | |||
686 | /* Command Frame Received notification. [WHCI] section 3.1.4.11. */ | ||
687 | struct uwb_rc_evt_cmd_frame_rcv { | ||
688 | struct uwb_rceb rceb; | ||
689 | __le16 receive_time; | ||
690 | struct uwb_dev_addr wSrcAddr; | ||
691 | struct uwb_dev_addr wDstAddr; | ||
692 | __le16 control; | ||
693 | __le16 reserved; | ||
694 | __le16 dataLength; | ||
695 | u8 data[]; | ||
696 | } __attribute__((packed)); | ||
697 | |||
698 | /* Channel Change IE Received notification. [WHCI] section 3.1.4.12. */ | ||
699 | struct uwb_rc_evt_channel_change_ie_rcv { | ||
700 | struct uwb_rceb rceb; | ||
701 | struct uwb_dev_addr wSrcAddr; | ||
702 | __le16 wIELength; | ||
703 | u8 IEData[]; | ||
704 | } __attribute__((packed)); | ||
705 | |||
706 | /* DAA Energy Detected notification. [WHCI 0.96] section 3.1.4.14. */ | ||
707 | struct uwb_rc_evt_daa_energy_detected { | ||
708 | struct uwb_rceb rceb; | ||
709 | __le16 wLength; | ||
710 | u8 bandID; | ||
711 | u8 reserved; | ||
712 | u8 toneBmp[16]; | ||
713 | } __attribute__((packed)); | ||
714 | |||
715 | |||
716 | /** | ||
717 | * Radio Control Interface Class Descriptor | ||
718 | * | ||
719 | * WUSB 1.0 [8.6.1.2] | ||
720 | */ | ||
721 | struct uwb_rc_control_intf_class_desc { | ||
722 | u8 bLength; | ||
723 | u8 bDescriptorType; | ||
724 | __le16 bcdRCIVersion; | ||
725 | } __attribute__((packed)); | ||
726 | |||
727 | #endif /* #ifndef __LINUX__UWB_SPEC_H__ */ | ||
diff --git a/include/linux/uwb/umc.h b/include/linux/uwb/umc.h new file mode 100644 index 000000000000..36a39e34f8d7 --- /dev/null +++ b/include/linux/uwb/umc.h | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * UWB Multi-interface Controller support. | ||
3 | * | ||
4 | * Copyright (C) 2007 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This file is released under the GPLv2 | ||
7 | * | ||
8 | * UMC (UWB Multi-interface Controller) capabilities (e.g., radio | ||
9 | * controller, host controller) are presented as devices on the "umc" | ||
10 | * bus. | ||
11 | * | ||
12 | * The radio controller is not strictly a UMC capability but it's | ||
13 | * useful to present it as such. | ||
14 | * | ||
15 | * References: | ||
16 | * | ||
17 | * [WHCI] Wireless Host Controller Interface Specification for | ||
18 | * Certified Wireless Universal Serial Bus, revision 0.95. | ||
19 | * | ||
20 | * How this works is kind of convoluted but simple. The whci.ko driver | ||
21 | * loads when WHCI devices are detected. These WHCI devices expose | ||
22 | * many devices in the same PCI function (they couldn't have reused | ||
23 | * functions, no), so for each PCI function that exposes these many | ||
24 | * devices, whci ceates a umc_dev [whci_probe() -> whci_add_cap()] | ||
25 | * with umc_device_create() and adds it to the bus with | ||
26 | * umc_device_register(). | ||
27 | * | ||
28 | * umc_device_register() calls device_register() which will push the | ||
29 | * bus management code to load your UMC driver's somehting_probe() | ||
30 | * that you have registered for that capability code. | ||
31 | * | ||
32 | * Now when the WHCI device is removed, whci_remove() will go over | ||
33 | * each umc_dev assigned to each of the PCI function's capabilities | ||
34 | * and through whci_del_cap() call umc_device_unregister() each | ||
35 | * created umc_dev. Of course, if you are bound to the device, your | ||
36 | * driver's something_remove() will be called. | ||
37 | */ | ||
38 | |||
39 | #ifndef _LINUX_UWB_UMC_H_ | ||
40 | #define _LINUX_UWB_UMC_H_ | ||
41 | |||
42 | #include <linux/device.h> | ||
43 | #include <linux/pci.h> | ||
44 | |||
45 | /* | ||
46 | * UMC capability IDs. | ||
47 | * | ||
48 | * 0x00 is reserved so use it for the radio controller device. | ||
49 | * | ||
50 | * [WHCI] table 2-8 | ||
51 | */ | ||
52 | #define UMC_CAP_ID_WHCI_RC 0x00 /* radio controller */ | ||
53 | #define UMC_CAP_ID_WHCI_WUSB_HC 0x01 /* WUSB host controller */ | ||
54 | |||
55 | /** | ||
56 | * struct umc_dev - UMC capability device | ||
57 | * | ||
58 | * @version: version of the specification this capability conforms to. | ||
59 | * @cap_id: capability ID. | ||
60 | * @bar: PCI Bar (64 bit) where the resource lies | ||
61 | * @resource: register space resource. | ||
62 | * @irq: interrupt line. | ||
63 | */ | ||
64 | struct umc_dev { | ||
65 | u16 version; | ||
66 | u8 cap_id; | ||
67 | u8 bar; | ||
68 | struct resource resource; | ||
69 | unsigned irq; | ||
70 | struct device dev; | ||
71 | }; | ||
72 | |||
73 | #define to_umc_dev(d) container_of(d, struct umc_dev, dev) | ||
74 | |||
75 | /** | ||
76 | * struct umc_driver - UMC capability driver | ||
77 | * @cap_id: supported capability ID. | ||
78 | * @match: driver specific capability matching function. | ||
79 | * @match_data: driver specific data for match() (e.g., a | ||
80 | * table of pci_device_id's if umc_match_pci_id() is used). | ||
81 | */ | ||
82 | struct umc_driver { | ||
83 | char *name; | ||
84 | u8 cap_id; | ||
85 | int (*match)(struct umc_driver *, struct umc_dev *); | ||
86 | const void *match_data; | ||
87 | |||
88 | int (*probe)(struct umc_dev *); | ||
89 | void (*remove)(struct umc_dev *); | ||
90 | int (*suspend)(struct umc_dev *, pm_message_t state); | ||
91 | int (*resume)(struct umc_dev *); | ||
92 | |||
93 | struct device_driver driver; | ||
94 | }; | ||
95 | |||
96 | #define to_umc_driver(d) container_of(d, struct umc_driver, driver) | ||
97 | |||
98 | extern struct bus_type umc_bus_type; | ||
99 | |||
100 | struct umc_dev *umc_device_create(struct device *parent, int n); | ||
101 | int __must_check umc_device_register(struct umc_dev *umc); | ||
102 | void umc_device_unregister(struct umc_dev *umc); | ||
103 | |||
104 | int __must_check __umc_driver_register(struct umc_driver *umc_drv, | ||
105 | struct module *mod, | ||
106 | const char *mod_name); | ||
107 | |||
108 | /** | ||
109 | * umc_driver_register - register a UMC capabiltity driver. | ||
110 | * @umc_drv: pointer to the driver. | ||
111 | */ | ||
112 | static inline int __must_check umc_driver_register(struct umc_driver *umc_drv) | ||
113 | { | ||
114 | return __umc_driver_register(umc_drv, THIS_MODULE, KBUILD_MODNAME); | ||
115 | } | ||
116 | void umc_driver_unregister(struct umc_driver *umc_drv); | ||
117 | |||
118 | /* | ||
119 | * Utility function you can use to match (umc_driver->match) against a | ||
120 | * null-terminated array of 'struct pci_device_id' in | ||
121 | * umc_driver->match_data. | ||
122 | */ | ||
123 | int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc); | ||
124 | |||
125 | /** | ||
126 | * umc_parent_pci_dev - return the UMC's parent PCI device or NULL if none | ||
127 | * @umc_dev: UMC device whose parent PCI device we are looking for | ||
128 | * | ||
129 | * DIRTY!!! DON'T RELY ON THIS | ||
130 | * | ||
131 | * FIXME: This is as dirty as it gets, but we need some way to check | ||
132 | * the correct type of umc_dev->parent (so that for example, we can | ||
133 | * cast to pci_dev). Casting to pci_dev is necesary because at some | ||
134 | * point we need to request resources from the device. Mapping is | ||
135 | * easily over come (ioremap and stuff are bus agnostic), but hooking | ||
136 | * up to some error handlers (such as pci error handlers) might need | ||
137 | * this. | ||
138 | * | ||
139 | * THIS might (probably will) be removed in the future, so don't count | ||
140 | * on it. | ||
141 | */ | ||
142 | static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev) | ||
143 | { | ||
144 | struct pci_dev *pci_dev = NULL; | ||
145 | if (umc_dev->dev.parent->bus == &pci_bus_type) | ||
146 | pci_dev = to_pci_dev(umc_dev->dev.parent); | ||
147 | return pci_dev; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * umc_dev_get() - reference a UMC device. | ||
152 | * @umc_dev: Pointer to UMC device. | ||
153 | * | ||
154 | * NOTE: we are assuming in this whole scheme that the parent device | ||
155 | * is referenced at _probe() time and unreferenced at _remove() | ||
156 | * time by the parent's subsystem. | ||
157 | */ | ||
158 | static inline struct umc_dev *umc_dev_get(struct umc_dev *umc_dev) | ||
159 | { | ||
160 | get_device(&umc_dev->dev); | ||
161 | return umc_dev; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * umc_dev_put() - unreference a UMC device. | ||
166 | * @umc_dev: Pointer to UMC device. | ||
167 | */ | ||
168 | static inline void umc_dev_put(struct umc_dev *umc_dev) | ||
169 | { | ||
170 | put_device(&umc_dev->dev); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * umc_set_drvdata - set UMC device's driver data. | ||
175 | * @umc_dev: Pointer to UMC device. | ||
176 | * @data: Data to set. | ||
177 | */ | ||
178 | static inline void umc_set_drvdata(struct umc_dev *umc_dev, void *data) | ||
179 | { | ||
180 | dev_set_drvdata(&umc_dev->dev, data); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * umc_get_drvdata - recover UMC device's driver data. | ||
185 | * @umc_dev: Pointer to UMC device. | ||
186 | */ | ||
187 | static inline void *umc_get_drvdata(struct umc_dev *umc_dev) | ||
188 | { | ||
189 | return dev_get_drvdata(&umc_dev->dev); | ||
190 | } | ||
191 | |||
192 | int umc_controller_reset(struct umc_dev *umc); | ||
193 | |||
194 | #endif /* #ifndef _LINUX_UWB_UMC_H_ */ | ||
diff --git a/include/linux/uwb/whci.h b/include/linux/uwb/whci.h new file mode 100644 index 000000000000..915ec23042d4 --- /dev/null +++ b/include/linux/uwb/whci.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * | ||
23 | * References: | ||
24 | * [WHCI] Wireless Host Controller Interface Specification for | ||
25 | * Certified Wireless Universal Serial Bus, revision 0.95. | ||
26 | */ | ||
27 | #ifndef _LINUX_UWB_WHCI_H_ | ||
28 | #define _LINUX_UWB_WHCI_H_ | ||
29 | |||
30 | #include <linux/pci.h> | ||
31 | |||
32 | /* | ||
33 | * UWB interface capability registers (offsets from UWBBASE) | ||
34 | * | ||
35 | * [WHCI] section 2.2 | ||
36 | */ | ||
37 | #define UWBCAPINFO 0x00 /* == UWBCAPDATA(0) */ | ||
38 | # define UWBCAPINFO_TO_N_CAPS(c) (((c) >> 0) & 0xFull) | ||
39 | #define UWBCAPDATA(n) (8*(n)) | ||
40 | # define UWBCAPDATA_TO_VERSION(c) (((c) >> 32) & 0xFFFFull) | ||
41 | # define UWBCAPDATA_TO_OFFSET(c) (((c) >> 18) & 0x3FFFull) | ||
42 | # define UWBCAPDATA_TO_BAR(c) (((c) >> 16) & 0x3ull) | ||
43 | # define UWBCAPDATA_TO_SIZE(c) ((((c) >> 8) & 0xFFull) * sizeof(u32)) | ||
44 | # define UWBCAPDATA_TO_CAP_ID(c) (((c) >> 0) & 0xFFull) | ||
45 | |||
46 | /* Size of the WHCI capability data (including the RC capability) for | ||
47 | a device with n capabilities. */ | ||
48 | #define UWBCAPDATA_SIZE(n) (8 + 8*(n)) | ||
49 | |||
50 | |||
51 | /* | ||
52 | * URC registers (offsets from URCBASE) | ||
53 | * | ||
54 | * [WHCI] section 2.3 | ||
55 | */ | ||
56 | #define URCCMD 0x00 | ||
57 | # define URCCMD_RESET (1 << 31) /* UMC Hardware reset */ | ||
58 | # define URCCMD_RS (1 << 30) /* Run/Stop */ | ||
59 | # define URCCMD_EARV (1 << 29) /* Event Address Register Valid */ | ||
60 | # define URCCMD_ACTIVE (1 << 15) /* Command is active */ | ||
61 | # define URCCMD_IWR (1 << 14) /* Interrupt When Ready */ | ||
62 | # define URCCMD_SIZE_MASK 0x00000fff /* Command size mask */ | ||
63 | #define URCSTS 0x04 | ||
64 | # define URCSTS_EPS (1 << 17) /* Event Processing Status */ | ||
65 | # define URCSTS_HALTED (1 << 16) /* RC halted */ | ||
66 | # define URCSTS_HSE (1 << 10) /* Host System Error...fried */ | ||
67 | # define URCSTS_ER (1 << 9) /* Event Ready */ | ||
68 | # define URCSTS_RCI (1 << 8) /* Ready for Command Interrupt */ | ||
69 | # define URCSTS_INT_MASK 0x00000700 /* URC interrupt sources */ | ||
70 | # define URCSTS_ISI 0x000000ff /* Interrupt Source Identification */ | ||
71 | #define URCINTR 0x08 | ||
72 | # define URCINTR_EN_ALL 0x000007ff /* Enable all interrupt sources */ | ||
73 | #define URCCMDADDR 0x10 | ||
74 | #define URCEVTADDR 0x18 | ||
75 | # define URCEVTADDR_OFFSET_MASK 0xfff /* Event pointer offset mask */ | ||
76 | |||
77 | |||
78 | /** Write 32 bit @value to little endian register at @addr */ | ||
79 | static inline | ||
80 | void le_writel(u32 value, void __iomem *addr) | ||
81 | { | ||
82 | iowrite32(value, addr); | ||
83 | } | ||
84 | |||
85 | |||
86 | /** Read from 32 bit little endian register at @addr */ | ||
87 | static inline | ||
88 | u32 le_readl(void __iomem *addr) | ||
89 | { | ||
90 | return ioread32(addr); | ||
91 | } | ||
92 | |||
93 | |||
94 | /** Write 64 bit @value to little endian register at @addr */ | ||
95 | static inline | ||
96 | void le_writeq(u64 value, void __iomem *addr) | ||
97 | { | ||
98 | iowrite32(value, addr); | ||
99 | iowrite32(value >> 32, addr + 4); | ||
100 | } | ||
101 | |||
102 | |||
103 | /** Read from 64 bit little endian register at @addr */ | ||
104 | static inline | ||
105 | u64 le_readq(void __iomem *addr) | ||
106 | { | ||
107 | u64 value; | ||
108 | value = ioread32(addr); | ||
109 | value |= (u64)ioread32(addr + 4) << 32; | ||
110 | return value; | ||
111 | } | ||
112 | |||
113 | extern int whci_wait_for(struct device *dev, u32 __iomem *reg, | ||
114 | u32 mask, u32 result, | ||
115 | unsigned long max_ms, const char *tag); | ||
116 | |||
117 | #endif /* #ifndef _LINUX_UWB_WHCI_H_ */ | ||
diff --git a/include/linux/wlp.h b/include/linux/wlp.h new file mode 100644 index 000000000000..033545e145c7 --- /dev/null +++ b/include/linux/wlp.h | |||
@@ -0,0 +1,735 @@ | |||
1 | /* | ||
2 | * WiMedia Logical Link Control Protocol (WLP) | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Reinette Chatre <reinette.chatre@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * FIXME: docs | ||
23 | * | ||
24 | * - Does not (yet) include support for WLP control frames | ||
25 | * WLP Draft 0.99 [6.5]. | ||
26 | * | ||
27 | * A visual representation of the data structures. | ||
28 | * | ||
29 | * wssidB wssidB | ||
30 | * ^ ^ | ||
31 | * | | | ||
32 | * wssidA wssidA | ||
33 | * wlp interface { ^ ^ | ||
34 | * ... | | | ||
35 | * ... ... wssid wssid ... | ||
36 | * wlp --- ... | | | ||
37 | * }; neighbors --> neighbA --> neighbB | ||
38 | * ... | ||
39 | * wss | ||
40 | * ... | ||
41 | * eda cache --> neighborA --> neighborB --> neighborC ... | ||
42 | */ | ||
43 | |||
44 | #ifndef __LINUX__WLP_H_ | ||
45 | #define __LINUX__WLP_H_ | ||
46 | |||
47 | #include <linux/netdevice.h> | ||
48 | #include <linux/skbuff.h> | ||
49 | #include <linux/list.h> | ||
50 | #include <linux/uwb.h> | ||
51 | |||
52 | /** | ||
53 | * WLP Protocol ID | ||
54 | * WLP Draft 0.99 [6.2] | ||
55 | * | ||
56 | * The MUX header for all WLP frames | ||
57 | */ | ||
58 | #define WLP_PROTOCOL_ID 0x0100 | ||
59 | |||
60 | /** | ||
61 | * WLP Version | ||
62 | * WLP version placed in the association frames (WLP 0.99 [6.6]) | ||
63 | */ | ||
64 | #define WLP_VERSION 0x10 | ||
65 | |||
66 | /** | ||
67 | * Bytes needed to print UUID as string | ||
68 | */ | ||
69 | #define WLP_WSS_UUID_STRSIZE 48 | ||
70 | |||
71 | /** | ||
72 | * Bytes needed to print nonce as string | ||
73 | */ | ||
74 | #define WLP_WSS_NONCE_STRSIZE 48 | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Size used for WLP name size | ||
79 | * | ||
80 | * The WSS name is set to 65 bytes, 1 byte larger than the maximum | ||
81 | * allowed by the WLP spec. This is to have a null terminated string | ||
82 | * for display to the user. A maximum of 64 bytes will still be used | ||
83 | * when placing the WSS name field in association frames. | ||
84 | */ | ||
85 | #define WLP_WSS_NAME_SIZE 65 | ||
86 | |||
87 | /** | ||
88 | * Number of bytes added by WLP to data frame | ||
89 | * | ||
90 | * A data frame transmitted from a host will be placed in a Standard or | ||
91 | * Abbreviated WLP frame. These have an extra 4 bytes of header (struct | ||
92 | * wlp_frame_std_abbrv_hdr). | ||
93 | * When the stack sends this data frame for transmission it needs to ensure | ||
94 | * there is enough headroom for this header. | ||
95 | */ | ||
96 | #define WLP_DATA_HLEN 4 | ||
97 | |||
98 | /** | ||
99 | * State of device regarding WLP Service Set | ||
100 | * | ||
101 | * WLP_WSS_STATE_NONE: the host does not participate in any WSS | ||
102 | * WLP_WSS_STATE_PART_ENROLLED: used as part of the enrollment sequence | ||
103 | * ("Partial Enroll"). This state is used to | ||
104 | * indicate the first part of enrollment that is | ||
105 | * unsecure. If the WSS is unsecure then the | ||
106 | * state will promptly go to WLP_WSS_STATE_ENROLLED, | ||
107 | * if the WSS is not secure then the enrollment | ||
108 | * procedure is a few more steps before we are | ||
109 | * enrolled. | ||
110 | * WLP_WSS_STATE_ENROLLED: the host is enrolled in a WSS | ||
111 | * WLP_WSS_STATE_ACTIVE: WSS is activated | ||
112 | * WLP_WSS_STATE_CONNECTED: host is connected to neighbor in WSS | ||
113 | * | ||
114 | */ | ||
115 | enum wlp_wss_state { | ||
116 | WLP_WSS_STATE_NONE = 0, | ||
117 | WLP_WSS_STATE_PART_ENROLLED, | ||
118 | WLP_WSS_STATE_ENROLLED, | ||
119 | WLP_WSS_STATE_ACTIVE, | ||
120 | WLP_WSS_STATE_CONNECTED, | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * WSS Secure status | ||
125 | * WLP 0.99 Table 6 | ||
126 | * | ||
127 | * Set to one if the WSS is secure, zero if it is not secure | ||
128 | */ | ||
129 | enum wlp_wss_sec_status { | ||
130 | WLP_WSS_UNSECURE = 0, | ||
131 | WLP_WSS_SECURE, | ||
132 | }; | ||
133 | |||
134 | /** | ||
135 | * WLP frame type | ||
136 | * WLP Draft 0.99 [6.2 Table 1] | ||
137 | */ | ||
138 | enum wlp_frame_type { | ||
139 | WLP_FRAME_STANDARD = 0, | ||
140 | WLP_FRAME_ABBREVIATED, | ||
141 | WLP_FRAME_CONTROL, | ||
142 | WLP_FRAME_ASSOCIATION, | ||
143 | }; | ||
144 | |||
145 | /** | ||
146 | * WLP Association Message Type | ||
147 | * WLP Draft 0.99 [6.6.1.2 Table 8] | ||
148 | */ | ||
149 | enum wlp_assoc_type { | ||
150 | WLP_ASSOC_D1 = 2, | ||
151 | WLP_ASSOC_D2 = 3, | ||
152 | WLP_ASSOC_M1 = 4, | ||
153 | WLP_ASSOC_M2 = 5, | ||
154 | WLP_ASSOC_M3 = 7, | ||
155 | WLP_ASSOC_M4 = 8, | ||
156 | WLP_ASSOC_M5 = 9, | ||
157 | WLP_ASSOC_M6 = 10, | ||
158 | WLP_ASSOC_M7 = 11, | ||
159 | WLP_ASSOC_M8 = 12, | ||
160 | WLP_ASSOC_F0 = 14, | ||
161 | WLP_ASSOC_E1 = 32, | ||
162 | WLP_ASSOC_E2 = 33, | ||
163 | WLP_ASSOC_C1 = 34, | ||
164 | WLP_ASSOC_C2 = 35, | ||
165 | WLP_ASSOC_C3 = 36, | ||
166 | WLP_ASSOC_C4 = 37, | ||
167 | }; | ||
168 | |||
169 | /** | ||
170 | * WLP Attribute Type | ||
171 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
172 | */ | ||
173 | enum wlp_attr_type { | ||
174 | WLP_ATTR_AUTH = 0x1005, /* Authenticator */ | ||
175 | WLP_ATTR_DEV_NAME = 0x1011, /* Device Name */ | ||
176 | WLP_ATTR_DEV_PWD_ID = 0x1012, /* Device Password ID */ | ||
177 | WLP_ATTR_E_HASH1 = 0x1014, /* E-Hash1 */ | ||
178 | WLP_ATTR_E_HASH2 = 0x1015, /* E-Hash2 */ | ||
179 | WLP_ATTR_E_SNONCE1 = 0x1016, /* E-SNonce1 */ | ||
180 | WLP_ATTR_E_SNONCE2 = 0x1017, /* E-SNonce2 */ | ||
181 | WLP_ATTR_ENCR_SET = 0x1018, /* Encrypted Settings */ | ||
182 | WLP_ATTR_ENRL_NONCE = 0x101A, /* Enrollee Nonce */ | ||
183 | WLP_ATTR_KEYWRAP_AUTH = 0x101E, /* Key Wrap Authenticator */ | ||
184 | WLP_ATTR_MANUF = 0x1021, /* Manufacturer */ | ||
185 | WLP_ATTR_MSG_TYPE = 0x1022, /* Message Type */ | ||
186 | WLP_ATTR_MODEL_NAME = 0x1023, /* Model Name */ | ||
187 | WLP_ATTR_MODEL_NR = 0x1024, /* Model Number */ | ||
188 | WLP_ATTR_PUB_KEY = 0x1032, /* Public Key */ | ||
189 | WLP_ATTR_REG_NONCE = 0x1039, /* Registrar Nonce */ | ||
190 | WLP_ATTR_R_HASH1 = 0x103D, /* R-Hash1 */ | ||
191 | WLP_ATTR_R_HASH2 = 0x103E, /* R-Hash2 */ | ||
192 | WLP_ATTR_R_SNONCE1 = 0x103F, /* R-SNonce1 */ | ||
193 | WLP_ATTR_R_SNONCE2 = 0x1040, /* R-SNonce2 */ | ||
194 | WLP_ATTR_SERIAL = 0x1042, /* Serial number */ | ||
195 | WLP_ATTR_UUID_E = 0x1047, /* UUID-E */ | ||
196 | WLP_ATTR_UUID_R = 0x1048, /* UUID-R */ | ||
197 | WLP_ATTR_PRI_DEV_TYPE = 0x1054, /* Primary Device Type */ | ||
198 | WLP_ATTR_SEC_DEV_TYPE = 0x1055, /* Secondary Device Type */ | ||
199 | WLP_ATTR_PORT_DEV = 0x1056, /* Portable Device */ | ||
200 | WLP_ATTR_APP_EXT = 0x1058, /* Application Extension */ | ||
201 | WLP_ATTR_WLP_VER = 0x2000, /* WLP Version */ | ||
202 | WLP_ATTR_WSSID = 0x2001, /* WSSID */ | ||
203 | WLP_ATTR_WSS_NAME = 0x2002, /* WSS Name */ | ||
204 | WLP_ATTR_WSS_SEC_STAT = 0x2003, /* WSS Secure Status */ | ||
205 | WLP_ATTR_WSS_BCAST = 0x2004, /* WSS Broadcast Address */ | ||
206 | WLP_ATTR_WSS_M_KEY = 0x2005, /* WSS Master Key */ | ||
207 | WLP_ATTR_ACC_ENRL = 0x2006, /* Accepting Enrollment */ | ||
208 | WLP_ATTR_WSS_INFO = 0x2007, /* WSS Information */ | ||
209 | WLP_ATTR_WSS_SEL_MTHD = 0x2008, /* WSS Selection Method */ | ||
210 | WLP_ATTR_ASSC_MTHD_LIST = 0x2009, /* Association Methods List */ | ||
211 | WLP_ATTR_SEL_ASSC_MTHD = 0x200A, /* Selected Association Method */ | ||
212 | WLP_ATTR_ENRL_HASH_COMM = 0x200B, /* Enrollee Hash Commitment */ | ||
213 | WLP_ATTR_WSS_TAG = 0x200C, /* WSS Tag */ | ||
214 | WLP_ATTR_WSS_VIRT = 0x200D, /* WSS Virtual EUI-48 */ | ||
215 | WLP_ATTR_WLP_ASSC_ERR = 0x200E, /* WLP Association Error */ | ||
216 | WLP_ATTR_VNDR_EXT = 0x200F, /* Vendor Extension */ | ||
217 | }; | ||
218 | |||
219 | /** | ||
220 | * WLP Category ID of primary/secondary device | ||
221 | * WLP Draft 0.99 [6.6.1.8 Table 12] | ||
222 | */ | ||
223 | enum wlp_dev_category_id { | ||
224 | WLP_DEV_CAT_COMPUTER = 1, | ||
225 | WLP_DEV_CAT_INPUT, | ||
226 | WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER, | ||
227 | WLP_DEV_CAT_CAMERA, | ||
228 | WLP_DEV_CAT_STORAGE, | ||
229 | WLP_DEV_CAT_INFRASTRUCTURE, | ||
230 | WLP_DEV_CAT_DISPLAY, | ||
231 | WLP_DEV_CAT_MULTIM, | ||
232 | WLP_DEV_CAT_GAMING, | ||
233 | WLP_DEV_CAT_TELEPHONE, | ||
234 | WLP_DEV_CAT_OTHER = 65535, | ||
235 | }; | ||
236 | |||
237 | /** | ||
238 | * WLP WSS selection method | ||
239 | * WLP Draft 0.99 [6.6.1.6 Table 10] | ||
240 | */ | ||
241 | enum wlp_wss_sel_mthd { | ||
242 | WLP_WSS_ENRL_SELECT = 1, /* Enrollee selects */ | ||
243 | WLP_WSS_REG_SELECT, /* Registrar selects */ | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * WLP association error values | ||
248 | * WLP Draft 0.99 [6.6.1.5 Table 9] | ||
249 | */ | ||
250 | enum wlp_assc_error { | ||
251 | WLP_ASSOC_ERROR_NONE, | ||
252 | WLP_ASSOC_ERROR_AUTH, /* Authenticator Failure */ | ||
253 | WLP_ASSOC_ERROR_ROGUE, /* Rogue activity suspected */ | ||
254 | WLP_ASSOC_ERROR_BUSY, /* Device busy */ | ||
255 | WLP_ASSOC_ERROR_LOCK, /* Setup Locked */ | ||
256 | WLP_ASSOC_ERROR_NOT_READY, /* Registrar not ready */ | ||
257 | WLP_ASSOC_ERROR_INV, /* Invalid WSS selection */ | ||
258 | WLP_ASSOC_ERROR_MSG_TIME, /* Message timeout */ | ||
259 | WLP_ASSOC_ERROR_ENR_TIME, /* Enrollment session timeout */ | ||
260 | WLP_ASSOC_ERROR_PW, /* Device password invalid */ | ||
261 | WLP_ASSOC_ERROR_VER, /* Unsupported version */ | ||
262 | WLP_ASSOC_ERROR_INT, /* Internal error */ | ||
263 | WLP_ASSOC_ERROR_UNDEF, /* Undefined error */ | ||
264 | WLP_ASSOC_ERROR_NUM, /* Numeric comparison failure */ | ||
265 | WLP_ASSOC_ERROR_WAIT, /* Waiting for user input */ | ||
266 | }; | ||
267 | |||
268 | /** | ||
269 | * WLP Parameters | ||
270 | * WLP 0.99 [7.7] | ||
271 | */ | ||
272 | enum wlp_parameters { | ||
273 | WLP_PER_MSG_TIMEOUT = 15, /* Seconds to wait for response to | ||
274 | association message. */ | ||
275 | }; | ||
276 | |||
277 | /** | ||
278 | * WLP IE | ||
279 | * | ||
280 | * The WLP IE should be included in beacons by all devices. | ||
281 | * | ||
282 | * The driver can set only a few of the fields in this information element, | ||
283 | * most fields are managed by the device self. When the driver needs to set | ||
284 | * a field it will only provide values for the fields of interest, the rest | ||
285 | * will be filled with zeroes. The fields of interest are: | ||
286 | * | ||
287 | * Element ID | ||
288 | * Length | ||
289 | * Capabilities (only to include WSSID Hash list length) | ||
290 | * WSSID Hash List fields | ||
291 | * | ||
292 | * WLP 0.99 [6.7] | ||
293 | * | ||
294 | * Only the fields that will be used are detailed in this structure, rest | ||
295 | * are not detailed or marked as "notused". | ||
296 | */ | ||
297 | struct wlp_ie { | ||
298 | struct uwb_ie_hdr hdr; | ||
299 | __le16 capabilities; | ||
300 | __le16 cycle_param; | ||
301 | __le16 acw_anchor_addr; | ||
302 | u8 wssid_hash_list[]; | ||
303 | } __attribute__((packed)); | ||
304 | |||
305 | static inline int wlp_ie_hash_length(struct wlp_ie *ie) | ||
306 | { | ||
307 | return (le16_to_cpu(ie->capabilities) >> 12) & 0xf; | ||
308 | } | ||
309 | |||
310 | static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length) | ||
311 | { | ||
312 | u16 caps = le16_to_cpu(ie->capabilities); | ||
313 | caps = (caps & ~(0xf << 12)) | (hash_length << 12); | ||
314 | ie->capabilities = cpu_to_le16(caps); | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * WLP nonce | ||
319 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
320 | * | ||
321 | * A 128-bit random number often used (E-SNonce1, E-SNonce2, Enrollee | ||
322 | * Nonce, Registrar Nonce, R-SNonce1, R-SNonce2). It is passed to HW so | ||
323 | * it is packed. | ||
324 | */ | ||
325 | struct wlp_nonce { | ||
326 | u8 data[16]; | ||
327 | } __attribute__((packed)); | ||
328 | |||
329 | /** | ||
330 | * WLP UUID | ||
331 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
332 | * | ||
333 | * Universally Unique Identifier (UUID) encoded as an octet string in the | ||
334 | * order the octets are shown in string representation in RFC4122. A UUID | ||
335 | * is often used (UUID-E, UUID-R, WSSID). It is passed to HW so it is packed. | ||
336 | */ | ||
337 | struct wlp_uuid { | ||
338 | u8 data[16]; | ||
339 | } __attribute__((packed)); | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Primary and secondary device type attributes | ||
344 | * WLP Draft 0.99 [6.6.1.8] | ||
345 | */ | ||
346 | struct wlp_dev_type { | ||
347 | enum wlp_dev_category_id category:16; | ||
348 | u8 OUI[3]; | ||
349 | u8 OUIsubdiv; | ||
350 | __le16 subID; | ||
351 | } __attribute__((packed)); | ||
352 | |||
353 | /** | ||
354 | * WLP frame header | ||
355 | * WLP Draft 0.99 [6.2] | ||
356 | */ | ||
357 | struct wlp_frame_hdr { | ||
358 | __le16 mux_hdr; /* WLP_PROTOCOL_ID */ | ||
359 | enum wlp_frame_type type:8; | ||
360 | } __attribute__((packed)); | ||
361 | |||
362 | /** | ||
363 | * WLP attribute field header | ||
364 | * WLP Draft 0.99 [6.6.1] | ||
365 | * | ||
366 | * Header of each attribute found in an association frame | ||
367 | */ | ||
368 | struct wlp_attr_hdr { | ||
369 | __le16 type; | ||
370 | __le16 length; | ||
371 | } __attribute__((packed)); | ||
372 | |||
373 | /** | ||
374 | * Device information commonly used together | ||
375 | * | ||
376 | * Each of these device information elements has a specified range in which it | ||
377 | * should fit (WLP 0.99 [Table 6]). This range provided in the spec does not | ||
378 | * include the termination null '\0' character (when used in the | ||
379 | * association protocol the attribute fields are accompanied | ||
380 | * with a "length" field so the full range from the spec can be used for | ||
381 | * the value). We thus allocate an extra byte to be able to store a string | ||
382 | * of max length with a terminating '\0'. | ||
383 | */ | ||
384 | struct wlp_device_info { | ||
385 | char name[33]; | ||
386 | char model_name[33]; | ||
387 | char manufacturer[65]; | ||
388 | char model_nr[33]; | ||
389 | char serial[33]; | ||
390 | struct wlp_dev_type prim_dev_type; | ||
391 | }; | ||
392 | |||
393 | /** | ||
394 | * Macros for the WLP attributes | ||
395 | * | ||
396 | * There are quite a few attributes (total is 43). The attribute layout can be | ||
397 | * in one of three categories: one value, an array, an enum forced to 8 bits. | ||
398 | * These macros help with their definitions. | ||
399 | */ | ||
400 | #define wlp_attr(type, name) \ | ||
401 | struct wlp_attr_##name { \ | ||
402 | struct wlp_attr_hdr hdr; \ | ||
403 | type name; \ | ||
404 | } __attribute__((packed)); | ||
405 | |||
406 | #define wlp_attr_array(type, name) \ | ||
407 | struct wlp_attr_##name { \ | ||
408 | struct wlp_attr_hdr hdr; \ | ||
409 | type name[]; \ | ||
410 | } __attribute__((packed)); | ||
411 | |||
412 | /** | ||
413 | * WLP association attribute fields | ||
414 | * WLP Draft 0.99 [6.6.1 Table 6] | ||
415 | * | ||
416 | * Attributes appear in same order as the Table in the spec | ||
417 | * FIXME Does not define all attributes yet | ||
418 | */ | ||
419 | |||
420 | /* Device name: Friendly name of sending device */ | ||
421 | wlp_attr_array(u8, dev_name) | ||
422 | |||
423 | /* Enrollee Nonce: Random number generated by enrollee for an enrollment | ||
424 | * session */ | ||
425 | wlp_attr(struct wlp_nonce, enonce) | ||
426 | |||
427 | /* Manufacturer name: Name of manufacturer of the sending device */ | ||
428 | wlp_attr_array(u8, manufacturer) | ||
429 | |||
430 | /* WLP Message Type */ | ||
431 | wlp_attr(u8, msg_type) | ||
432 | |||
433 | /* WLP Model name: Model name of sending device */ | ||
434 | wlp_attr_array(u8, model_name) | ||
435 | |||
436 | /* WLP Model number: Model number of sending device */ | ||
437 | wlp_attr_array(u8, model_nr) | ||
438 | |||
439 | /* Registrar Nonce: Random number generated by registrar for an enrollment | ||
440 | * session */ | ||
441 | wlp_attr(struct wlp_nonce, rnonce) | ||
442 | |||
443 | /* Serial number of device */ | ||
444 | wlp_attr_array(u8, serial) | ||
445 | |||
446 | /* UUID of enrollee */ | ||
447 | wlp_attr(struct wlp_uuid, uuid_e) | ||
448 | |||
449 | /* UUID of registrar */ | ||
450 | wlp_attr(struct wlp_uuid, uuid_r) | ||
451 | |||
452 | /* WLP Primary device type */ | ||
453 | wlp_attr(struct wlp_dev_type, prim_dev_type) | ||
454 | |||
455 | /* WLP Secondary device type */ | ||
456 | wlp_attr(struct wlp_dev_type, sec_dev_type) | ||
457 | |||
458 | /* WLP protocol version */ | ||
459 | wlp_attr(u8, version) | ||
460 | |||
461 | /* WLP service set identifier */ | ||
462 | wlp_attr(struct wlp_uuid, wssid) | ||
463 | |||
464 | /* WLP WSS name */ | ||
465 | wlp_attr_array(u8, wss_name) | ||
466 | |||
467 | /* WLP WSS Secure Status */ | ||
468 | wlp_attr(u8, wss_sec_status) | ||
469 | |||
470 | /* WSS Broadcast Address */ | ||
471 | wlp_attr(struct uwb_mac_addr, wss_bcast) | ||
472 | |||
473 | /* WLP Accepting Enrollment */ | ||
474 | wlp_attr(u8, accept_enrl) | ||
475 | |||
476 | /** | ||
477 | * WSS information attributes | ||
478 | * WLP Draft 0.99 [6.6.3 Table 15] | ||
479 | */ | ||
480 | struct wlp_wss_info { | ||
481 | struct wlp_attr_wssid wssid; | ||
482 | struct wlp_attr_wss_name name; | ||
483 | struct wlp_attr_accept_enrl accept; | ||
484 | struct wlp_attr_wss_sec_status sec_stat; | ||
485 | struct wlp_attr_wss_bcast bcast; | ||
486 | } __attribute__((packed)); | ||
487 | |||
488 | /* WLP WSS Information */ | ||
489 | wlp_attr_array(struct wlp_wss_info, wss_info) | ||
490 | |||
491 | /* WLP WSS Selection method */ | ||
492 | wlp_attr(u8, wss_sel_mthd) | ||
493 | |||
494 | /* WLP WSS tag */ | ||
495 | wlp_attr(u8, wss_tag) | ||
496 | |||
497 | /* WSS Virtual Address */ | ||
498 | wlp_attr(struct uwb_mac_addr, wss_virt) | ||
499 | |||
500 | /* WLP association error */ | ||
501 | wlp_attr(u8, wlp_assc_err) | ||
502 | |||
503 | /** | ||
504 | * WLP standard and abbreviated frames | ||
505 | * | ||
506 | * WLP Draft 0.99 [6.3] and [6.4] | ||
507 | * | ||
508 | * The difference between the WLP standard frame and the WLP | ||
509 | * abbreviated frame is that the standard frame includes the src | ||
510 | * and dest addresses from the Ethernet header, the abbreviated frame does | ||
511 | * not. | ||
512 | * The src/dest (as well as the type/length and client data) are already | ||
513 | * defined as part of the Ethernet header, we do not do this here. | ||
514 | * From this perspective the standard and abbreviated frames appear the | ||
515 | * same - they will be treated differently though. | ||
516 | * | ||
517 | * The size of this header is also captured in WLP_DATA_HLEN to enable | ||
518 | * interfaces to prepare their headroom. | ||
519 | */ | ||
520 | struct wlp_frame_std_abbrv_hdr { | ||
521 | struct wlp_frame_hdr hdr; | ||
522 | u8 tag; | ||
523 | } __attribute__((packed)); | ||
524 | |||
525 | /** | ||
526 | * WLP association frames | ||
527 | * | ||
528 | * WLP Draft 0.99 [6.6] | ||
529 | */ | ||
530 | struct wlp_frame_assoc { | ||
531 | struct wlp_frame_hdr hdr; | ||
532 | enum wlp_assoc_type type:8; | ||
533 | struct wlp_attr_version version; | ||
534 | struct wlp_attr_msg_type msg_type; | ||
535 | u8 attr[]; | ||
536 | } __attribute__((packed)); | ||
537 | |||
538 | /* Ethernet to dev address mapping */ | ||
539 | struct wlp_eda { | ||
540 | spinlock_t lock; | ||
541 | struct list_head cache; /* Eth<->Dev Addr cache */ | ||
542 | }; | ||
543 | |||
544 | /** | ||
545 | * WSS information temporary storage | ||
546 | * | ||
547 | * This information is only stored temporarily during discovery. It should | ||
548 | * not be stored unless the device is enrolled in the advertised WSS. This | ||
549 | * is done mainly because we follow the letter of the spec in this regard. | ||
550 | * See WLP 0.99 [7.2.3]. | ||
551 | * When the device does become enrolled in a WSS the WSS information will | ||
552 | * be stored as part of the more comprehensive struct wlp_wss. | ||
553 | */ | ||
554 | struct wlp_wss_tmp_info { | ||
555 | char name[WLP_WSS_NAME_SIZE]; | ||
556 | u8 accept_enroll; | ||
557 | u8 sec_status; | ||
558 | struct uwb_mac_addr bcast; | ||
559 | }; | ||
560 | |||
561 | struct wlp_wssid_e { | ||
562 | struct list_head node; | ||
563 | struct wlp_uuid wssid; | ||
564 | struct wlp_wss_tmp_info *info; | ||
565 | }; | ||
566 | |||
567 | /** | ||
568 | * A cache entry of WLP neighborhood | ||
569 | * | ||
570 | * @node: head of list is wlp->neighbors | ||
571 | * @wssid: list of wssids of this neighbor, element is wlp_wssid_e | ||
572 | * @info: temporary storage for information learned during discovery. This | ||
573 | * storage is used together with the wssid_e temporary storage | ||
574 | * during discovery. | ||
575 | */ | ||
576 | struct wlp_neighbor_e { | ||
577 | struct list_head node; | ||
578 | struct wlp_uuid uuid; | ||
579 | struct uwb_dev *uwb_dev; | ||
580 | struct list_head wssid; /* Elements are wlp_wssid_e */ | ||
581 | struct wlp_device_info *info; | ||
582 | }; | ||
583 | |||
584 | struct wlp; | ||
585 | /** | ||
586 | * Information for an association session in progress. | ||
587 | * | ||
588 | * @exp_message: The type of the expected message. Both this message and a | ||
589 | * F0 message (which can be sent in response to any | ||
590 | * association frame) will be accepted as a valid message for | ||
591 | * this session. | ||
592 | * @cb: The function that will be called upon receipt of this | ||
593 | * message. | ||
594 | * @cb_priv: Private data of callback | ||
595 | * @data: Data used in association process (always a sk_buff?) | ||
596 | * @neighbor: Address of neighbor with which association session is in | ||
597 | * progress. | ||
598 | */ | ||
599 | struct wlp_session { | ||
600 | enum wlp_assoc_type exp_message; | ||
601 | void (*cb)(struct wlp *); | ||
602 | void *cb_priv; | ||
603 | void *data; | ||
604 | struct uwb_dev_addr neighbor_addr; | ||
605 | }; | ||
606 | |||
607 | /** | ||
608 | * WLP Service Set | ||
609 | * | ||
610 | * @mutex: used to protect entire WSS structure. | ||
611 | * | ||
612 | * @name: The WSS name is set to 65 bytes, 1 byte larger than the maximum | ||
613 | * allowed by the WLP spec. This is to have a null terminated string | ||
614 | * for display to the user. A maximum of 64 bytes will still be used | ||
615 | * when placing the WSS name field in association frames. | ||
616 | * | ||
617 | * @accept_enroll: Accepting enrollment: Set to one if registrar is | ||
618 | * accepting enrollment in WSS, or zero otherwise. | ||
619 | * | ||
620 | * Global and local information for each WSS in which we are enrolled. | ||
621 | * WLP 0.99 Section 7.2.1 and Section 7.2.2 | ||
622 | */ | ||
623 | struct wlp_wss { | ||
624 | struct mutex mutex; | ||
625 | struct kobject kobj; | ||
626 | /* Global properties. */ | ||
627 | struct wlp_uuid wssid; | ||
628 | u8 hash; | ||
629 | char name[WLP_WSS_NAME_SIZE]; | ||
630 | struct uwb_mac_addr bcast; | ||
631 | u8 secure_status:1; | ||
632 | u8 master_key[16]; | ||
633 | /* Local properties. */ | ||
634 | u8 tag; | ||
635 | struct uwb_mac_addr virtual_addr; | ||
636 | /* Extra */ | ||
637 | u8 accept_enroll:1; | ||
638 | enum wlp_wss_state state; | ||
639 | }; | ||
640 | |||
641 | /** | ||
642 | * WLP main structure | ||
643 | * @mutex: protect changes to WLP structure. We only allow changes to the | ||
644 | * uuid, so currently this mutex only protects this field. | ||
645 | */ | ||
646 | struct wlp { | ||
647 | struct mutex mutex; | ||
648 | struct uwb_rc *rc; /* UWB radio controller */ | ||
649 | struct uwb_pal pal; | ||
650 | struct wlp_eda eda; | ||
651 | struct wlp_uuid uuid; | ||
652 | struct wlp_session *session; | ||
653 | struct wlp_wss wss; | ||
654 | struct mutex nbmutex; /* Neighbor mutex protects neighbors list */ | ||
655 | struct list_head neighbors; /* Elements are wlp_neighbor_e */ | ||
656 | struct uwb_notifs_handler uwb_notifs_handler; | ||
657 | struct wlp_device_info *dev_info; | ||
658 | void (*fill_device_info)(struct wlp *wlp, struct wlp_device_info *info); | ||
659 | int (*xmit_frame)(struct wlp *, struct sk_buff *, | ||
660 | struct uwb_dev_addr *); | ||
661 | void (*stop_queue)(struct wlp *); | ||
662 | void (*start_queue)(struct wlp *); | ||
663 | }; | ||
664 | |||
665 | /* sysfs */ | ||
666 | |||
667 | |||
668 | struct wlp_wss_attribute { | ||
669 | struct attribute attr; | ||
670 | ssize_t (*show)(struct wlp_wss *wss, char *buf); | ||
671 | ssize_t (*store)(struct wlp_wss *wss, const char *buf, size_t count); | ||
672 | }; | ||
673 | |||
674 | #define WSS_ATTR(_name, _mode, _show, _store) \ | ||
675 | static struct wlp_wss_attribute wss_attr_##_name = __ATTR(_name, _mode, \ | ||
676 | _show, _store) | ||
677 | |||
678 | extern int wlp_setup(struct wlp *, struct uwb_rc *); | ||
679 | extern void wlp_remove(struct wlp *); | ||
680 | extern ssize_t wlp_neighborhood_show(struct wlp *, char *); | ||
681 | extern int wlp_wss_setup(struct net_device *, struct wlp_wss *); | ||
682 | extern void wlp_wss_remove(struct wlp_wss *); | ||
683 | extern ssize_t wlp_wss_activate_show(struct wlp_wss *, char *); | ||
684 | extern ssize_t wlp_wss_activate_store(struct wlp_wss *, const char *, size_t); | ||
685 | extern ssize_t wlp_eda_show(struct wlp *, char *); | ||
686 | extern ssize_t wlp_eda_store(struct wlp *, const char *, size_t); | ||
687 | extern ssize_t wlp_uuid_show(struct wlp *, char *); | ||
688 | extern ssize_t wlp_uuid_store(struct wlp *, const char *, size_t); | ||
689 | extern ssize_t wlp_dev_name_show(struct wlp *, char *); | ||
690 | extern ssize_t wlp_dev_name_store(struct wlp *, const char *, size_t); | ||
691 | extern ssize_t wlp_dev_manufacturer_show(struct wlp *, char *); | ||
692 | extern ssize_t wlp_dev_manufacturer_store(struct wlp *, const char *, size_t); | ||
693 | extern ssize_t wlp_dev_model_name_show(struct wlp *, char *); | ||
694 | extern ssize_t wlp_dev_model_name_store(struct wlp *, const char *, size_t); | ||
695 | extern ssize_t wlp_dev_model_nr_show(struct wlp *, char *); | ||
696 | extern ssize_t wlp_dev_model_nr_store(struct wlp *, const char *, size_t); | ||
697 | extern ssize_t wlp_dev_serial_show(struct wlp *, char *); | ||
698 | extern ssize_t wlp_dev_serial_store(struct wlp *, const char *, size_t); | ||
699 | extern ssize_t wlp_dev_prim_category_show(struct wlp *, char *); | ||
700 | extern ssize_t wlp_dev_prim_category_store(struct wlp *, const char *, | ||
701 | size_t); | ||
702 | extern ssize_t wlp_dev_prim_OUI_show(struct wlp *, char *); | ||
703 | extern ssize_t wlp_dev_prim_OUI_store(struct wlp *, const char *, size_t); | ||
704 | extern ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *, char *); | ||
705 | extern ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *, const char *, | ||
706 | size_t); | ||
707 | extern ssize_t wlp_dev_prim_subcat_show(struct wlp *, char *); | ||
708 | extern ssize_t wlp_dev_prim_subcat_store(struct wlp *, const char *, | ||
709 | size_t); | ||
710 | extern int wlp_receive_frame(struct device *, struct wlp *, struct sk_buff *, | ||
711 | struct uwb_dev_addr *); | ||
712 | extern int wlp_prepare_tx_frame(struct device *, struct wlp *, | ||
713 | struct sk_buff *, struct uwb_dev_addr *); | ||
714 | void wlp_reset_all(struct wlp *wlp); | ||
715 | |||
716 | /** | ||
717 | * Initialize WSS | ||
718 | */ | ||
719 | static inline | ||
720 | void wlp_wss_init(struct wlp_wss *wss) | ||
721 | { | ||
722 | mutex_init(&wss->mutex); | ||
723 | } | ||
724 | |||
725 | static inline | ||
726 | void wlp_init(struct wlp *wlp) | ||
727 | { | ||
728 | INIT_LIST_HEAD(&wlp->neighbors); | ||
729 | mutex_init(&wlp->mutex); | ||
730 | mutex_init(&wlp->nbmutex); | ||
731 | wlp_wss_init(&wlp->wss); | ||
732 | } | ||
733 | |||
734 | |||
735 | #endif /* #ifndef __LINUX__WLP_H_ */ | ||
diff --git a/lib/bitmap.c b/lib/bitmap.c index 482df94ea21e..1338469ac849 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
@@ -996,3 +996,25 @@ int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) | |||
996 | return 0; | 996 | return 0; |
997 | } | 997 | } |
998 | EXPORT_SYMBOL(bitmap_allocate_region); | 998 | EXPORT_SYMBOL(bitmap_allocate_region); |
999 | |||
1000 | /** | ||
1001 | * bitmap_copy_le - copy a bitmap, putting the bits into little-endian order. | ||
1002 | * @dst: destination buffer | ||
1003 | * @src: bitmap to copy | ||
1004 | * @nbits: number of bits in the bitmap | ||
1005 | * | ||
1006 | * Require nbits % BITS_PER_LONG == 0. | ||
1007 | */ | ||
1008 | void bitmap_copy_le(void *dst, const unsigned long *src, int nbits) | ||
1009 | { | ||
1010 | unsigned long *d = dst; | ||
1011 | int i; | ||
1012 | |||
1013 | for (i = 0; i < nbits/BITS_PER_LONG; i++) { | ||
1014 | if (BITS_PER_LONG == 64) | ||
1015 | d[i] = cpu_to_le64(src[i]); | ||
1016 | else | ||
1017 | d[i] = cpu_to_le32(src[i]); | ||
1018 | } | ||
1019 | } | ||
1020 | EXPORT_SYMBOL(bitmap_copy_le); | ||