add patch 0011-ps3stor-send-cmd-timeout.patch
[ps3linux_kernel_patches_314.git] / 0150-ps3jupiter.patch
blob34ad03f32354615e9ae13a76fd8e05954cd0eb02
1 --- a/drivers/net/wireless/Kconfig 2013-07-18 03:19:44.349296942 +0200
2 +++ b/drivers/net/wireless/Kconfig 2013-07-18 03:20:20.909299068 +0200
3 @@ -281,5 +281,6 @@
4 source "drivers/net/wireless/zd1211rw/Kconfig"
5 source "drivers/net/wireless/mwifiex/Kconfig"
6 source "drivers/net/wireless/cw1200/Kconfig"
7 +source "drivers/net/wireless/ps3jupiter/Kconfig"
9 endif # WLAN
10 --- a/drivers/net/wireless/Makefile 2013-07-18 03:19:51.919297381 +0200
11 +++ b/drivers/net/wireless/Makefile 2013-07-18 03:20:40.309300197 +0200
12 @@ -59,3 +59,5 @@
13 obj-$(CONFIG_BRCMSMAC) += brcm80211/
15 obj-$(CONFIG_CW1200) += cw1200/
17 +obj-$(CONFIG_PS3_JUPITER) += ps3jupiter/
18 --- /dev/null 2012-01-06 10:29:22.673734242 +0100
19 +++ b/drivers/net/wireless/ps3jupiter/Kconfig 2012-01-06 12:13:47.507142753 +0100
20 @@ -0,0 +1,16 @@
22 +config PS3_JUPITER
23 + tristate "PS3 Jupiter 802.11bg support"
24 + depends on USB
25 + ---help---
26 + A driver for the PS3 Jupiter
27 + 802.11bg wireless network adapter.
29 +config PS3_JUPITER_STA
30 + tristate "PS3 Jupiter 802.11bg station support"
31 + depends on PS3_JUPITER
32 + select WIRELESS_EXT
33 + select WEXT_PRIV
34 + ---help---
35 + A station driver for the PS3 Jupiter
36 + 802.11bg wireless network adapter.
37 --- /dev/null 2012-01-06 10:29:22.673734242 +0100
38 +++ b/drivers/net/wireless/ps3jupiter/Makefile 2012-01-06 12:07:05.647715657 +0100
39 @@ -0,0 +1,3 @@
41 +obj-$(CONFIG_PS3_JUPITER) += ps3_jupiter.o
42 +obj-$(CONFIG_PS3_JUPITER_STA) += ps3_jupiter_sta.o
43 --- /dev/null 2012-11-01 00:09:58.397610712 -0800
44 +++ b/drivers/net/wireless/ps3jupiter/ps3_eurus.h 2012-11-01 03:22:11.000000000 -0800
45 @@ -0,0 +1,605 @@
47 +/*
48 + * PS3 Eurus
49 + *
50 + * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
51 + * All rights reserved.
52 + *
53 + * This program is free software; you can redistribute it and/or modify it
54 + * under the terms of the GNU General Public License as published
55 + * by the Free Software Foundation; version 2 of the License.
56 + *
57 + * This program is distributed in the hope that it will be useful, but
58 + * WITHOUT ANY WARRANTY; without even the implied warranty of
59 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
60 + * General Public License for more details.
61 + *
62 + * You should have received a copy of the GNU General Public License along
63 + * with this program; if not, write to the Free Software Foundation, Inc.,
64 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
65 + */
67 +#ifndef _PS3_EURUS_H
68 +#define _PS3_EURUS_H
70 +enum ps3_eurus_cmd_id {
71 + PS3_EURUS_CMD_0x1 = 0x0001,
72 + PS3_EURUS_CMD_GET_AP_SSID = 0x0003,
73 + PS3_EURUS_CMD_SET_AP_SSID = 0x0005,
74 + PS3_EURUS_CMD_GET_CHANNEL = 0x000f,
75 + PS3_EURUS_CMD_SET_CHANNEL = 0x0011,
76 + PS3_EURUS_CMD_SET_ANTENNA = 0x0029,
77 + PS3_EURUS_CMD_GET_AP_WEP_CONFIG = 0x0059,
78 + PS3_EURUS_CMD_SET_AP_WEP_CONFIG = 0x005b,
79 + PS3_EURUS_CMD_0x61 = 0x0061,
80 + PS3_EURUS_CMD_0x65 = 0x0065,
81 + PS3_EURUS_CMD_GET_FW_VERSION = 0x0099,
82 + PS3_EURUS_CMD_GET_AP_OPMODE = 0x00b7,
83 + PS3_EURUS_CMD_SET_AP_OPMODE = 0x00b9,
84 + PS3_EURUS_CMD_0xc5 = 0x00c5,
85 + PS3_EURUS_CMD_GET_AP_WPA_AKM_SUITE = 0x00c8,
86 + PS3_EURUS_CMD_SET_AP_WPA_AKM_SUITE = 0x00c9,
87 + PS3_EURUS_CMD_GET_AP_WPA_GROUP_CIPHER_SUITE = 0x00cd,
88 + PS3_EURUS_CMD_SET_AP_WPA_GROUP_CIPHER_SUITE = 0x00cf,
89 + PS3_EURUS_CMD_GET_AP_WPA_PSK_PASSPHRASE = 0x00d1,
90 + PS3_EURUS_CMD_SET_AP_WPA_PSK_PASSPHRASE = 0x00d3,
91 + PS3_EURUS_CMD_0xd5 = 0x00d5,
92 + PS3_EURUS_CMD_0x127 = 0x0127,
93 + PS3_EURUS_CMD_0x12b = 0x012b,
94 + PS3_EURUS_CMD_GET_AP_WPA_PSK_BIN = 0x017b,
95 + PS3_EURUS_CMD_SET_AP_WPA_PSK_BIN = 0x017d,
96 + PS3_EURUS_CMD_GET_AP_WPA_PAIRWISE_CIPHER_SUITE = 0x01bd,
97 + PS3_EURUS_CMD_SET_AP_WPA_PAIRWISE_CIPHER_SUITE = 0x01bf,
98 + PS3_EURUS_CMD_0x1d9 = 0x01d9,
99 + PS3_EURUS_CMD_START_AP = 0x01dd,
100 + PS3_EURUS_CMD_0x1ed = 0x01ed,
101 + PS3_EURUS_CMD_GET_HW_REVISION = 0x01fb,
102 + PS3_EURUS_CMD_0x203 = 0x0203,
103 + PS3_EURUS_CMD_0x207 = 0x0207,
104 + PS3_EURUS_CMD_ASSOCIATE = 0x1001,
105 + PS3_EURUS_CMD_GET_COMMON_CONFIG = 0x1003,
106 + PS3_EURUS_CMD_SET_COMMON_CONFIG = 0x1005,
107 + PS3_EURUS_CMD_GET_WEP_CONFIG = 0x1013,
108 + PS3_EURUS_CMD_SET_WEP_CONFIG = 0x1015,
109 + PS3_EURUS_CMD_GET_WPA_CONFIG = 0x1017,
110 + PS3_EURUS_CMD_SET_WPA_CONFIG = 0x1019,
111 + PS3_EURUS_CMD_0x1025 = 0x1025,
112 + PS3_EURUS_CMD_0x1031 = 0x1031,
113 + PS3_EURUS_CMD_GET_SCAN_RESULTS = 0x1033,
114 + PS3_EURUS_CMD_START_SCAN = 0x1035,
115 + PS3_EURUS_CMD_DISASSOCIATE = 0x1037,
116 + PS3_EURUS_CMD_GET_RSSI = 0x103d,
117 + PS3_EURUS_CMD_GET_MAC_ADDR = 0x103f,
118 + PS3_EURUS_CMD_SET_MAC_ADDR = 0x1041,
119 + PS3_EURUS_CMD_0x104d = 0x104d,
120 + PS3_EURUS_CMD_0x104f = 0x104f,
121 + PS3_EURUS_CMD_0x105f = 0x105f,
122 + PS3_EURUS_CMD_0x1109 = 0x1109,
123 + PS3_EURUS_CMD_0x110b = 0x110b,
124 + PS3_EURUS_CMD_0x110d = 0x110d,
125 + PS3_EURUS_CMD_0x1133 = 0x1133,
126 + PS3_EURUS_CMD_0x114b = 0x114b,
127 + PS3_EURUS_CMD_0x114f = 0x114f,
128 + PS3_EURUS_CMD_0x115b = 0x115b,
129 + PS3_EURUS_CMD_0x115d = 0x115d,
130 + PS3_EURUS_CMD_0x115f = 0x115f,
131 + PS3_EURUS_CMD_SET_MCAST_ADDR_FILTER = 0x1161,
132 + PS3_EURUS_CMD_CLEAR_MCAST_ADDR_FILTER = 0x1163,
133 + PS3_EURUS_CMD_GET_MCAST_ADDR_FILTER = 0x1165,
134 + PS3_EURUS_CMD_0x116d = 0x116d,
135 + PS3_EURUS_CMD_0x116f = 0x116f,
136 + PS3_EURUS_CMD_GET_MAC_ADDR_LIST = 0x1117,
137 + PS3_EURUS_CMD_0x1171 = 0x1171,
138 + PS3_EURUS_CMD_GET_CHANNEL_INFO = 0xfffd,
141 +enum ps3_eurus_cmd_status {
142 + PS3_EURUS_CMD_OK = 0x0001,
143 + PS3_EURUS_CMD_INVALID_LENGTH = 0x0002,
144 + PS3_EURUS_CMD_UNSUPPORTED = 0x0003,
145 + PS3_EURUS_CMD_INVALID_PARAMETER = 0x0004,
148 +enum ps3_eurus_event_type {
149 + PS3_EURUS_EVENT_TYPE_0x8 = 0x00000008,
150 + PS3_EURUS_EVENT_TYPE_0x10 = 0x00000010,
151 + PS3_EURUS_EVENT_TYPE_0x40 = 0x00000040,
152 + PS3_EURUS_EVENT_TYPE_0x80 = 0x00000080,
153 + PS3_EURUS_EVENT_TYPE_0x100 = 0x00000100,
154 + PS3_EURUS_EVENT_TYPE_0x400 = 0x00000400,
155 + PS3_EURUS_EVENT_TYPE_0x80000000 = 0x80000000
158 +enum ps3_eurus_event_id {
159 + /* event type 0x00000008 */
161 + PS3_EURUS_EVENT_STA_CONNECTED = 0x00000010,
163 + /* event type 0x00000010 */
165 + PS3_EURUS_EVENT_STA_DISCONNECTED = 0x00000002,
166 + PS3_EURUS_EVENT_AP_STOPPED = 0x00000004,
168 + /* event type 0x00000040 */
170 + PS3_EURUS_EVENT_DEAUTH = 0x00000001,
172 + /* event type 0x00000080 */
174 + PS3_EURUS_EVENT_BEACON_LOST = 0x00000001,
175 + PS3_EURUS_EVENT_CONNECTED = 0x00000002,
176 + PS3_EURUS_EVENT_SCAN_COMPLETED = 0x00000004,
177 + PS3_EURUS_EVENT_WPA_CONNECTED = 0x00000020,
178 + PS3_EURUS_EVENT_WPA_ERROR = 0x00000040,
180 + /* event type 0x00000100 */
182 + PS3_EURUS_EVENT_0x100_0x2 = 0x00000002,
183 + PS3_EURUS_EVENT_AP_STARTED = 0x00000010,
184 + PS3_EURUS_EVENT_STA_WPA_CONNECTED = 0x00000020,
185 + PS3_EURUS_EVENT_0x100_0x40 = 0x00000040,
187 + /* event type 0x80000000 */
189 + PS3_EURUS_EVENT_DEVICE_READY = 0x00000001,
192 +enum ps3_eurus_ap_opmode {
193 + PS3_EURUS_AP_OPMODE_11B = 0x00000000,
194 + PS3_EURUS_AP_OPMODE_11G = 0x00000001,
195 + PS3_EURUS_AP_OPMODE_11BG = 0x00000002,
198 +enum ps3_eurus_bss_type {
199 + PS3_EURUS_BSS_INFRA = 0x00,
200 + PS3_EURUS_BSS_ADHOC = 0x02,
203 +enum ps3_eurus_auth_mode {
204 + PS3_EURUS_AUTH_OPEN = 0x00,
205 + PS3_EURUS_AUTH_SHARED_KEY = 0x01,
208 +enum ps3_eurus_opmode {
209 + PS3_EURUS_OPMODE_11BG = 0x00,
210 + PS3_EURUS_OPMODE_11B = 0x01,
211 + PS3_EURUS_OPMODE_11G = 0x02,
214 +enum ps3_eurus_preamble_mode {
215 + PS3_EURUS_PREAMBLE_SHORT = 0x00,
216 + PS3_EURUS_PREAMBLE_LONG = 0x01,
219 +enum ps3_eurus_wep_security_mode {
220 + PS3_EURUS_WEP_SECURITY_NONE = 0x00,
221 + PS3_EURUS_WEP_SECURITY_40BIT = 0x01,
222 + PS3_EURUS_WEP_SECURITY_104BIT = 0x02,
225 +enum ps3_eurus_wpa_security_mode {
226 + PS3_EURUS_WPA_SECURITY_WPA = 0x00,
227 + PS3_EURUS_WPA_SECURITY_WPA2 = 0x01,
230 +enum ps3_eurus_wpa_psk_type {
231 + PS3_EURUS_WPA_PSK_PASSPHRASE = 0x00,
232 + PS3_EURUS_WPA_PSK_BIN = 0x01,
235 +enum ps3_eurus_wpa_cipher_suite {
236 + PS3_EURUS_WPA_CIPHER_SUITE_WPA_TKIP = 0x0050f202,
237 + PS3_EURUS_WPA_CIPHER_SUITE_WPA_AES = 0x0050f204,
238 + PS3_EURUS_WPA_CIPHER_SUITE_WPA2_TKIP = 0x000fac02,
239 + PS3_EURUS_WPA_CIPHER_SUITE_WPA2_AES = 0x000fac04,
242 +enum ps3_eurus_wpa_akm_suite {
243 + PS3_EURUS_WPA_AKM_SUITE_WPA_PSK = 0x0050f202,
244 + PS3_EURUS_WPA_AKM_SUITE_WPA2_PSK = 0x000fac02,
247 +struct ps3_eurus_cmd_hdr {
248 + __le16 id; /* enum ps3_eurus_cmd_id */
249 + __le16 tag;
250 + __le16 status; /* enum ps3_eurus_cmd_status */
251 + __le16 payload_length;
252 + u8 res[4];
253 +} __packed;
255 +struct ps3_eurus_cmd_0x1 {
256 + u8 unknown;
257 + u8 res[3];
258 +} __packed;
260 +struct ps3_eurus_cmd_ap_ssid {
261 + u8 ssid[32];
262 + u8 res[4];
263 +} __packed;
265 +struct ps3_eurus_cmd_get_channel {
266 + u8 unknown[35];
267 + __le16 channel;
268 +} __packed;
270 +struct ps3_eurus_cmd_set_channel {
271 + u8 channel;
272 +} __packed;
274 +struct ps3_eurus_cmd_set_antenna {
275 + u8 unknown1;
276 + u8 unknown2;
277 +} __packed;
279 +struct ps3_eurus_cmd_ap_wep_config {
280 + u8 unknown1;
281 + u8 unknown2;
282 + u8 security_mode; /* enum ps3_eurus_wep_security_mode */
283 + u8 unknown3;
284 + u8 key[4][18];
285 +} __packed;
287 +struct ps3_eurus_cmd_0x61 {
288 + u8 unknown;
289 +} __packed;
291 +struct ps3_eurus_cmd_0x65 {
292 + u8 unknown;
293 +} __packed;
295 +struct ps3_eurus_cmd_get_fw_version {
296 + u8 version[62]; /* string */
297 +} __packed;
299 +struct ps3_eurus_cmd_ap_opmode {
300 + __le32 opmode; /* enum ps3_eurus_ap_opmode */
301 +} __packed;
303 +struct ps3_eurus_cmd_0xc5 {
304 + __le32 unknown;
305 +} __packed;
307 +struct ps3_eurus_cmd_ap_wpa_akm_suite {
308 + __be32 suite; /* enum ps3_eurus_wpa_akm_suite */
309 + u8 unknown;
310 +} __packed;
312 +struct ps3_eurus_cmd_ap_wpa_group_cipher_suite {
313 + __be32 cipher_suite; /* enum ps3_eurus_wpa_cipher_suite */
314 +} __packed;
316 +struct ps3_eurus_cmd_ap_wpa_psk_passphrase {
317 + u8 passphrase[64];
318 +} __packed;
320 +struct ps3_eurus_cmd_0xd5 {
321 + __le32 unknown;
322 +} __packed;
324 +struct ps3_eurus_cmd_0x127 {
325 + u8 res[4];
326 +} __packed;
328 +struct ps3_eurus_cmd_0x12b {
329 + u8 res[4];
330 +} __packed;
332 +struct ps3_eurus_cmd_ap_wpa_psk_bin {
333 + u8 enable;
334 + u8 psk[32];
335 +} __packed;
337 +struct ps3_eurus_cmd_ap_wpa_pairwise_cipher_suite {
338 + __be32 cipher_suite; /* enum ps3_eurus_wpa_cipher_suite */
339 + u8 unknown;
340 +} __packed;
342 +struct ps3_eurus_cmd_0x1d9 {
343 + u8 unknown1;
344 + u8 unknown2;
345 + u8 res[2];
346 +} __packed;
348 +struct ps3_eurus_cmd_start_ap {
349 + u8 unknown;
350 +} __packed;
352 +struct ps3_eurus_cmd_0x1ed {
353 + __le32 unknown1;
354 + u8 unknown2;
355 + u8 unknown3;
356 + u8 unknown4;
357 + u8 unknown5;
358 + u8 unknown6;
359 + u8 unknown7;
360 + u8 unknown8;
361 +} __packed;
363 +struct ps3_eurus_cmd_get_hw_revision {
364 + u8 unknown[4];
365 +} __packed;
367 +struct ps3_eurus_cmd_0x203 {
368 + __le32 unknown;
369 +} __packed;
371 +struct ps3_eurus_cmd_0x207 {
372 + __le32 unknown;
373 +} __packed;
375 +struct ps3_eurus_cmd_associate {
376 + u8 unknown;
377 +} __packed;
379 +struct ps3_eurus_cmd_common_config {
380 + u8 bss_type; /* enum ps3_eurus_bss_type */
381 + u8 auth_mode; /* enum ps3_eurus_auth_mode */
382 + u8 opmode; /* enum ps3_eurus_opmode */
383 + u8 unknown;
384 + u8 bssid[6];
385 + __le16 capability;
386 + u8 ie[0];
387 +} __packed;
389 +struct ps3_eurus_cmd_wep_config {
390 + u8 unknown1;
391 + u8 security_mode; /* enum ps3_eurus_wep_security_mode */
392 + __le16 unknown2;
393 + u8 key[4][16];
394 +} __packed;
396 +struct ps3_eurus_cmd_wpa_config {
397 + u8 unknown;
398 + u8 security_mode; /* enum ps3_eurus_wpa_security_mode */
399 + u8 psk_type; /* enum ps3_eurus_wpa_psk_type */
400 + u8 psk[64];
401 + __be32 group_cipher_suite; /* enum ps3_eurus_wpa_cipher_suite */
402 + __be32 pairwise_cipher_suite; /* enum ps3_eurus_wpa_cipher_suite */
403 + __be32 akm_suite; /* enum ps3_eurus_wpa_akm_suite */
404 +} __packed;
406 +struct ps3_eurus_cmd_0x1025 {
407 + u8 preamble_mode; /* enum ps3_eurus_preamble_mode */
408 + u8 res[3];
409 +} __packed;
411 +struct ps3_eurus_cmd_0x1031 {
412 + u8 unknown1;
413 + u8 unknown2;
414 +} __packed;
416 +struct ps3_eurus_scan_result {
417 + __le16 length;
418 + u8 bssid[6];
419 + u8 rssi;
420 + __le64 timestamp;
421 + __le16 beacon_period; /* in msec */
422 + __le16 capability;
423 + u8 ie[0];
424 +} __packed;
426 +#define PS3_EURUS_SCAN_RESULTS_MAXSIZE 0x5b0
428 +struct ps3_eurus_cmd_get_scan_results {
429 + u8 count;
430 + struct ps3_eurus_scan_result result[0];
431 +} __packed;
433 +struct ps3_eurus_cmd_start_scan {
434 + u8 unknown1;
435 + u8 unknown2;
436 + __le16 channel_dwell; /* in msec */
437 + u8 res[6];
438 + u8 ie[0];
439 +} __packed;
441 +struct ps3_eurus_cmd_disassociate {
442 + u8 unknown;
443 +} __packed;
445 +struct ps3_eurus_cmd_get_rssi {
446 + u8 res[10];
447 + u8 rssi;
448 +} __packed;
450 +struct ps3_eurus_cmd_get_mac_addr {
451 + u8 unknown;
452 + u8 mac_addr[6];
453 +} __packed;
455 +struct ps3_eurus_cmd_set_mac_addr {
456 + u8 mac_addr[6];
457 +} __packed;
459 +struct ps3_eurus_cmd_0x104d {
460 + u8 unknown;
461 +} __packed;
463 +struct ps3_eurus_cmd_0x104f {
464 + u8 unknown;
465 +} __packed;
467 +struct ps3_eurus_cmd_0x105f {
468 + __le16 channel_info;
469 + u8 mac_addr[6];
470 + u8 unknown1;
471 + u8 unknown2;
472 +} __packed;
474 +struct ps3_eurus_cmd_0x1109 {
475 + __le16 unknown1;
476 + __le16 unknown2;
477 + __le16 unknown3;
478 + __le16 unknown4;
479 + __le16 unknown5;
480 + __le16 unknown6;
481 + __le16 unknown7;
482 + u8 unknown8;
483 + u8 res;
484 + u8 unknown9;
485 + u8 unknown10;
486 + __le16 unknown11;
487 + __le16 unknown12;
488 +} __packed;
490 +struct ps3_eurus_cmd_0x110b {
491 + __le32 unknown1;
492 + u8 res[4];
493 + __le32 unknown2;
494 +} __packed;
496 +struct ps3_eurus_cmd_0x110d {
497 + u8 res1[12];
498 + __le32 unknown1;
499 + __le32 unknown2;
500 + __le32 unknown3;
501 + __le32 unknown4;
502 + __le32 unknown5;
503 + __le32 unknown6;
504 + __le32 unknown7;
505 + u8 res2[88];
506 +} __packed;
508 +struct ps3_eurus_cmd_0x1133 {
509 + u8 unknown1;
510 + u8 unknown2;
511 + u8 unknown3;
512 + u8 unknown4;
513 + __le32 unknown5;
514 + u8 res[6];
515 +} __packed;
517 +struct ps3_eurus_cmd_0x114f {
518 + u8 res[1304];
519 +} __packed;
521 +struct ps3_eurus_cmd_0x115b {
522 + __le16 unknown1;
523 + __le16 unknown2;
524 + u8 mac_addr[6];
525 + u8 res[84];
526 +} __packed;
528 +struct ps3_eurus_cmd_mcast_addr_filter {
529 + __le32 word[8];
530 +} __packed;
532 +struct ps3_eurus_cmd_0x116d {
533 + __le32 unknown;
534 +} __packed;
536 +struct ps3_eurus_cmd_0x116f {
537 + __le32 unknown;
538 +} __packed;
540 +#define PS3_EURUS_MAC_ADDR_LIST_MAXSIZE 0xc2
542 +struct ps3_eurus_cmd_get_mac_addr_list {
543 + __le16 count; /* number of MAC addresses */
544 + u8 mac_addr[0];
545 +} __packed;
547 +struct ps3_eurus_cmd_get_channel_info {
548 + u16 channel_info;
549 +} __packed;
551 +struct ps3_eurus_event_hdr {
552 + __le32 type; /* enum ps3_eurus_event_type */
553 + __le32 id; /* enum ps3_eurus_event_id */
554 + __le32 timestamp;
555 + __le32 payload_length;
556 + __le32 unknown;
557 +} __packed;
559 +struct ps3_eurus_event {
560 + struct ps3_eurus_event_hdr hdr;
561 + u8 payload[44];
562 +} __packed;
565 + * ps3_eurus_rssi2percentage
566 + */
567 +static inline u8 ps3_eurus_rssi2percentage(u8 rssi)
569 + if (rssi > 89)
570 + return 1;
571 + else if (rssi < 50)
572 + return 100;
573 + else
574 + return ((90 - rssi) * 100) / 40;
577 +#define PS3_EURUS_MCAST_ADDR_HASH2VAL(h) (1 << ((h) & 0x1f))
578 +#define PS3_EURUS_MCAST_ADDR_HASH2POS(h) (((h) >> 5) & 0x7)
581 + * ps3_eurus_mcast_addr_hash
582 + */
583 +static inline u8 ps3_eurus_mcast_addr_hash(const u8 mac_addr[ETH_ALEN])
585 + u8 buf[ETH_ALEN];
586 + u32 h;
587 + unsigned int i, j;
589 + memcpy(buf, mac_addr, ETH_ALEN);
591 + /* reverse bits in each byte */
593 + for (i = 0; i < ETH_ALEN; i++) {
594 + buf[i] = (buf[i] >> 4) | ((buf[i] & 0xf) << 4);
595 + buf[i] = ((buf[i] & 0xcc) >> 2) | ((buf[i] & 0x33) << 2);
596 + buf[i] = ((buf[i] & 0xaa) >> 1) | ((buf[i] & 0x55) << 1);
599 + h = 0xffffffff;
601 + for (i = 0; i < ETH_ALEN; i++) {
602 + h = (((unsigned int) buf[i]) << 24) ^ h;
604 + for (j = 0; j < 8; j++) {
605 + if (((int) h) >= 0) {
606 + h = h << 1;
607 + } else {
608 + h = (h << 1) ^ 0x4c10000;
609 + h = h ^ 0x1db7;
614 + h = ((h >> 24) & 0xf8) | (h & 0x7);
616 + return (h & 0xff);
620 + * ps3_eurus_make_cmd_0x1109
621 + */
622 +static inline void ps3_eurus_make_cmd_0x1109(struct ps3_eurus_cmd_0x1109 *cmd_0x1109,
623 + u8 arg1, u16 arg2, u16 arg3, u16 arg4, u16 arg5)
625 + memset(cmd_0x1109, 0, sizeof(*cmd_0x1109));
627 + cmd_0x1109->unknown1 = cpu_to_le16(0x1);
628 + cmd_0x1109->unknown8 = arg1;
630 + if (arg1 == 0x0) {
631 + cmd_0x1109->unknown6 = cpu_to_le16(0xa);
632 + } else if (arg1 == 0x1) {
633 + cmd_0x1109->unknown2 = cpu_to_le16(arg2);
634 + cmd_0x1109->unknown3 = cpu_to_le16(arg3);
635 + cmd_0x1109->unknown4 = cpu_to_le16(arg5);
637 + if (arg2 == 0x0)
638 + cmd_0x1109->unknown5 = cpu_to_le16(0x6);
639 + else
640 + cmd_0x1109->unknown5 = cpu_to_le16(0x2);
642 + cmd_0x1109->unknown7 = cpu_to_le16(arg4);
643 + cmd_0x1109->unknown9 = 0xff;
644 + cmd_0x1109->unknown10 = 0xff;
645 + cmd_0x1109->unknown11 = 0xffff;
646 + cmd_0x1109->unknown12 = 0xffff;
650 +#endif
651 --- /dev/null 2012-11-01 00:09:58.397610712 -0800
652 +++ b/drivers/net/wireless/ps3jupiter/ps3_jupiter.h 2012-11-01 03:22:23.000000000 -0800
653 @@ -0,0 +1,34 @@
656 + * PS3 Jupiter
658 + * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
659 + * All rights reserved.
661 + * This program is free software; you can redistribute it and/or modify it
662 + * under the terms of the GNU General Public License as published
663 + * by the Free Software Foundation; version 2 of the License.
665 + * This program is distributed in the hope that it will be useful, but
666 + * WITHOUT ANY WARRANTY; without even the implied warranty of
667 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
668 + * General Public License for more details.
670 + * You should have received a copy of the GNU General Public License along
671 + * with this program; if not, write to the Free Software Foundation, Inc.,
672 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
673 + */
675 +#ifndef _PS3_JUPITER_H
676 +#define _PS3_JUPITER_H
678 +int ps3_jupiter_register_event_listener(struct notifier_block *listener);
680 +int ps3_jupiter_unregister_event_listener(struct notifier_block *listener);
682 +int ps3_jupiter_exec_eurus_cmd(enum ps3_eurus_cmd_id cmd,
683 + void *payload, unsigned int payload_length,
684 + unsigned int *response_status,
685 + unsigned int *response_length, void *response);
687 +#endif
688 --- /dev/null 2012-11-01 00:09:58.397610712 -0800
689 +++ b/drivers/net/wireless/ps3jupiter/ps3_jupiter.c 2012-11-01 03:22:27.000000000 -0800
690 @@ -0,0 +1,1245 @@
693 + * PS3 Jupiter
695 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
696 + * All rights reserved.
698 + * This program is free software; you can redistribute it and/or modify it
699 + * under the terms of the GNU General Public License as published
700 + * by the Free Software Foundation; version 2 of the License.
702 + * This program is distributed in the hope that it will be useful, but
703 + * WITHOUT ANY WARRANTY; without even the implied warranty of
704 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
705 + * General Public License for more details.
707 + * You should have received a copy of the GNU General Public License along
708 + * with this program; if not, write to the Free Software Foundation, Inc.,
709 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
710 + */
712 +#include <linux/module.h>
713 +#include <linux/kernel.h>
714 +#include <linux/init.h>
715 +#include <linux/slab.h>
716 +#include <linux/usb.h>
717 +#include <linux/notifier.h>
719 +#include <linux/etherdevice.h>
720 +#include <linux/if_ether.h>
722 +#include <asm/byteorder.h>
723 +#include <asm/ps3.h>
724 +#include <asm/lv1call.h>
726 +#include "ps3_eurus.h"
727 +#include "ps3_jupiter.h"
729 +#define PS3_JUPITER_EP 0x5
731 +#define PS3_JUPITER_IRQ_BUFSIZE 2048
732 +#define PS3_JUPITER_CMD_BUFSIZE 2048
734 +#define LV1_SB_BUS_ID 0x1
735 +#define LV1_GELIC_DEV_ID 0x0
736 +#define LV1_GET_MAC_ADDRESS 0x1
737 +#define LV1_GET_CHANNEL_INFO 0x6
739 +enum ps3_jupiter_pkt_type {
740 + PS3_JUPITER_PKT_CMD = 6,
741 + PS3_JUPITER_PKT_EVENT = 8,
744 +struct ps3_jupiter_dev {
745 + struct usb_device *udev;
746 + struct urb *irq_urb, *cmd_urb;
747 + void *irq_buf, *cmd_buf;
749 + u16 cmd_tag, eurus_cmd, eurus_tag;
750 + struct completion cmd_done_comp;
751 + spinlock_t cmd_lock;
752 + int cmd_busy, cmd_err;
754 + struct workqueue_struct *event_queue;
755 + struct delayed_work event_work;
756 + struct blocking_notifier_head event_listeners;
757 + struct list_head event_list;
758 + spinlock_t event_list_lock;
760 + struct notifier_block event_listener;
761 + struct completion event_comp;
763 + unsigned char mac_addr[ETH_ALEN];
764 + u64 channel_info;
766 + u16 dev_status;
767 + int dev_ready;
770 +struct ps3_jupiter_pkt_hdr {
771 + u8 unknown1;
772 + u8 unknown2;
773 + u8 type;
774 +} __packed;
776 +struct ps3_jupiter_cmd_hdr {
777 + u8 unknown1;
778 + __le16 unknown2;
779 + u8 res1[2];
780 + __le16 tag;
781 + u8 res2[14];
782 +} __packed;
784 +struct ps3_jupiter_event_hdr {
785 + u8 count;
786 +} __packed;
788 +struct ps3_jupiter_list_event {
789 + struct list_head list;
790 + struct ps3_eurus_event event;
793 +static struct ps3_jupiter_dev *ps3jd;
795 +static unsigned char ps3_jupiter_devkey[] = {
796 + 0x76, 0x4e, 0x4b, 0x07, 0x24, 0x42, 0x53, 0xfb, 0x5a, 0xc7, 0xcc, 0x1d, 0xae, 0x00, 0xc6, 0xd8,
797 + 0x14, 0x40, 0x61, 0x8b, 0x13, 0x17, 0x4d, 0x7c, 0x3b, 0xb6, 0x90, 0xb8, 0x6e, 0x8b, 0xbb, 0x1d,
801 + * ps3_jupiter_event_worker
802 + */
803 +static void ps3_jupiter_event_worker(struct work_struct *work)
805 + struct ps3_jupiter_dev *jd = container_of(work, struct ps3_jupiter_dev, event_work.work);
806 + struct ps3_jupiter_list_event *list_event;
807 + unsigned long flags;
809 + /* dispatch received events to each listener */
811 + while (1) {
812 + spin_lock_irqsave(&jd->event_list_lock, flags);
814 + if (list_empty(&jd->event_list)) {
815 + spin_unlock_irqrestore(&jd->event_list_lock, flags);
816 + break;
819 + list_event = list_entry(jd->event_list.next, struct ps3_jupiter_list_event, list);
820 + list_del(&list_event->list);
822 + spin_unlock_irqrestore(&jd->event_list_lock, flags);
824 + blocking_notifier_call_chain(&jd->event_listeners, 0, &list_event->event);
826 + kfree(list_event);
831 + * ps3_jupiter_event_irq
832 + */
833 +static void ps3_jupiter_event_irq(struct ps3_jupiter_dev *jd,
834 + void *buf, unsigned int length)
836 + struct usb_device *udev = jd->udev;
837 + struct ps3_jupiter_pkt_hdr *pkt_hdr;
838 + struct ps3_jupiter_event_hdr *event_hdr;
839 + struct ps3_jupiter_list_event *list_event;
840 + unsigned long flags;
841 + int i;
843 + dev_dbg(&udev->dev, "got event IRQ packet\n");
845 + if (length < sizeof(*pkt_hdr) + sizeof(*event_hdr)) {
846 + dev_err(&udev->dev, "got event IRQ packet with invalid length (%d)\n",
847 + length);
848 + return;
851 + pkt_hdr = (struct ps3_jupiter_pkt_hdr *) buf;
852 + event_hdr = (struct ps3_jupiter_event_hdr *) (pkt_hdr + 1);
854 + if (length < sizeof(*pkt_hdr) + sizeof(*event_hdr) +
855 + event_hdr->count * sizeof(struct ps3_eurus_event)) {
856 + dev_err(&udev->dev, "got event IRQ packet with invalid length (%d)\n",
857 + length);
858 + return;
861 + dev_dbg(&udev->dev, "got %d event(s)\n", event_hdr->count);
863 + for (i = 0; i < event_hdr->count; i++) {
864 + list_event = kmalloc(sizeof(*list_event), GFP_ATOMIC);
865 + if (!list_event) {
866 + dev_err(&udev->dev, "could not allocate memory for new event\n");
867 + continue;
870 + memcpy(&list_event->event, (unsigned char *) event_hdr + sizeof(*event_hdr) +
871 + i * sizeof(struct ps3_eurus_event), sizeof(struct ps3_eurus_event));
872 + list_event->event.hdr.type = le32_to_cpu(list_event->event.hdr.type);
873 + list_event->event.hdr.id = le32_to_cpu(list_event->event.hdr.id);
874 + list_event->event.hdr.timestamp = le32_to_cpu(list_event->event.hdr.timestamp);
875 + list_event->event.hdr.payload_length = le32_to_cpu(list_event->event.hdr.payload_length);
876 + list_event->event.hdr.unknown = le32_to_cpu(list_event->event.hdr.unknown);
878 + spin_lock_irqsave(&jd->event_list_lock, flags);
879 + list_add_tail(&list_event->list, &jd->event_list);
880 + spin_unlock_irqrestore(&jd->event_list_lock, flags);
883 + if (event_hdr->count)
884 + queue_delayed_work(jd->event_queue, &jd->event_work, 0);
888 + * ps3_jupiter_cmd_irq
889 + */
890 +static void ps3_jupiter_cmd_irq(struct ps3_jupiter_dev *jd,
891 + void *buf, unsigned int length)
893 + struct usb_device *udev = jd->udev;
894 + struct ps3_jupiter_pkt_hdr *pkt_hdr;
895 + struct ps3_jupiter_cmd_hdr *cmd_hdr;
896 + struct ps3_eurus_cmd_hdr *eurus_cmd_hdr;
897 + u16 cmd_tag, eurus_cmd, eurus_tag, payload_length;
899 + dev_dbg(&udev->dev, "got command IRQ packet\n");
901 + if (length < sizeof(*pkt_hdr) + sizeof(*cmd_hdr) + sizeof(*eurus_cmd_hdr)) {
902 + dev_err(&udev->dev, "got command IRQ packet with invalid length (%d)\n",
903 + length);
904 + return;
907 + pkt_hdr = (struct ps3_jupiter_pkt_hdr *) buf;
908 + cmd_hdr = (struct ps3_jupiter_cmd_hdr *) (pkt_hdr + 1);
909 + eurus_cmd_hdr = (struct ps3_eurus_cmd_hdr *) (cmd_hdr + 1);
910 + payload_length = le16_to_cpu(eurus_cmd_hdr->payload_length);
912 + if (length < sizeof(*pkt_hdr) + sizeof(*cmd_hdr) + sizeof(*eurus_cmd_hdr) + payload_length) {
913 + dev_err(&udev->dev, "got command IRQ packet with invalid length (%d)\n",
914 + length);
915 + return;
918 + cmd_tag = le16_to_cpu(cmd_hdr->tag);
920 + if (jd->cmd_tag != cmd_tag)
921 + dev_err(&udev->dev, "got command IRQ packet with invalid command tag, "
922 + "got (0x%04x), expected (0x%04x)\n", cmd_tag, jd->cmd_tag);
924 + eurus_cmd = le16_to_cpu(eurus_cmd_hdr->id);
926 + if ((jd->eurus_cmd + 1) != eurus_cmd)
927 + dev_err(&udev->dev, "got command IRQ packet with invalid EURUS command, "
928 + "got (0x%04x), expected (0x%04x)\n", eurus_cmd, jd->eurus_cmd);
930 + eurus_tag = le16_to_cpu(eurus_cmd_hdr->tag);
932 + if (jd->eurus_tag != eurus_tag)
933 + dev_err(&udev->dev, "got command IRQ packet with invalid EURUS tag, "
934 + "got (0x%04x), expected (0x%04x)\n", eurus_tag, jd->eurus_tag);
936 + memcpy(jd->cmd_buf, buf, length);
938 + jd->cmd_err = 0;
939 + complete(&jd->cmd_done_comp);
943 + * ps3_jupiter_irq_urb_complete
944 + */
945 +static void ps3_jupiter_irq_urb_complete(struct urb *urb)
947 + struct ps3_jupiter_dev *jd = urb->context;
948 + struct usb_device *udev = jd->udev;
949 + struct ps3_jupiter_pkt_hdr *pkt_hdr;
950 + int err;
952 + dev_dbg(&udev->dev, "IRQ URB completed (%d)\n", urb->status);
954 + switch (urb->status) {
955 + case 0:
956 + if (urb->actual_length < sizeof(*pkt_hdr)) {
957 + dev_err(&udev->dev, "got IRQ packet with invalid length (%d)\n",
958 + urb->actual_length);
959 + break;
962 + pkt_hdr = (struct ps3_jupiter_pkt_hdr *) jd->irq_buf;
964 + switch (pkt_hdr->type) {
965 + case PS3_JUPITER_PKT_CMD:
966 + ps3_jupiter_cmd_irq(jd, pkt_hdr, urb->actual_length);
967 + break;
968 + case PS3_JUPITER_PKT_EVENT:
969 + ps3_jupiter_event_irq(jd, pkt_hdr, urb->actual_length);
970 + break;
971 + default:
972 + dev_err(&udev->dev, "got unknown IRQ packet type (%d)\n",
973 + pkt_hdr->type);
975 + break;
976 + case -EINPROGRESS:
977 + /* ignore */
978 + break;
979 + case -ECONNRESET:
980 + case -ENOENT:
981 + case -ESHUTDOWN:
982 + case -ENODEV:
983 + return;
984 + default:
985 + dev_err(&udev->dev, "IRQ URB failed (%d)\n", urb->status);
988 + err = usb_submit_urb(jd->irq_urb, GFP_ATOMIC);
989 + if (err)
990 + dev_err(&udev->dev, "could not submit IRQ URB (%d)\n", err);
994 + * ps3_jupiter_cmd_urb_complete
995 + */
996 +static void ps3_jupiter_cmd_urb_complete(struct urb *urb)
998 + struct ps3_jupiter_dev *jd = urb->context;
999 + struct usb_device *udev = jd->udev;
1001 + dev_dbg(&udev->dev, "command URB completed (%d)\n", urb->status);
1003 + switch (urb->status) {
1004 + case 0:
1005 + /* success */
1006 + break;
1007 + case -EINPROGRESS:
1008 + /* ignore */
1009 + break;
1010 + case -ECONNRESET:
1011 + case -ENOENT:
1012 + case -ESHUTDOWN:
1013 + case -ENODEV:
1014 + default:
1015 + dev_err(&udev->dev, "command URB failed (%d)\n", urb->status);
1016 + jd->cmd_err = urb->status;
1017 + complete(&jd->cmd_done_comp);
1022 + * _ps3_jupiter_register_event_listener
1023 + */
1024 +static int _ps3_jupiter_register_event_listener(struct ps3_jupiter_dev *jd,
1025 + struct notifier_block *listener)
1027 + BUG_ON(!jd);
1029 + return blocking_notifier_chain_register(&jd->event_listeners, listener);
1033 + * ps3_jupiter_register_event_listener
1034 + */
1035 +int ps3_jupiter_register_event_listener(struct notifier_block *listener)
1037 + struct ps3_jupiter_dev *jd = ps3jd;
1038 + int err;
1040 + if (!jd || !jd->dev_ready)
1041 + return -ENODEV;
1043 + err = _ps3_jupiter_register_event_listener(jd, listener);
1045 + return err;
1048 +EXPORT_SYMBOL_GPL(ps3_jupiter_register_event_listener);
1051 + * _ps3_jupiter_unregister_event_listener
1052 + */
1053 +static int _ps3_jupiter_unregister_event_listener(struct ps3_jupiter_dev *jd,
1054 + struct notifier_block *listener)
1056 + BUG_ON(!jd);
1058 + return blocking_notifier_chain_unregister(&jd->event_listeners, listener);
1062 + * ps3_jupiter_unregister_event_listener
1063 + */
1064 +int ps3_jupiter_unregister_event_listener(struct notifier_block *listener)
1066 + struct ps3_jupiter_dev *jd = ps3jd;
1067 + int err;
1069 + if (!jd || !jd->dev_ready)
1070 + return -ENODEV;
1072 + err = _ps3_jupiter_unregister_event_listener(jd, listener);
1074 + return err;
1077 +EXPORT_SYMBOL_GPL(ps3_jupiter_unregister_event_listener);
1080 + * _ps3_jupiter_exec_eurus_cmd
1081 + */
1082 +static int _ps3_jupiter_exec_eurus_cmd(struct ps3_jupiter_dev *jd,
1083 + enum ps3_eurus_cmd_id cmd,
1084 + void *payload, unsigned int payload_length,
1085 + unsigned int *response_status,
1086 + unsigned int *response_length, void *response)
1088 + struct usb_device *udev = jd->udev;
1089 + struct ps3_jupiter_pkt_hdr *pkt_hdr;
1090 + struct ps3_jupiter_cmd_hdr *cmd_hdr;
1091 + struct ps3_eurus_cmd_hdr *eurus_cmd_hdr;
1092 + struct ps3_eurus_cmd_get_channel_info *eurus_cmd_get_channel_info;
1093 + u16 status;
1094 + unsigned long flags;
1095 + int err;
1097 + BUG_ON(!jd);
1099 + if (!payload && payload_length)
1100 + return -EINVAL;
1102 + spin_lock_irqsave(&jd->cmd_lock, flags);
1104 + if (jd->cmd_busy) {
1105 + spin_unlock_irqrestore(&jd->cmd_lock, flags);
1106 + dev_dbg(&udev->dev,
1107 + "trying to execute multiple commands at the same time\n");
1108 + return -EAGAIN;
1111 + jd->cmd_busy = 1;
1113 + spin_unlock_irqrestore(&jd->cmd_lock, flags);
1115 + dev_dbg(&udev->dev, "EURUS command 0x%04x payload length %d\n",
1116 + cmd, payload_length);
1118 + /* internal commands */
1120 + if (cmd == PS3_EURUS_CMD_GET_CHANNEL_INFO) {
1121 + if (payload_length < sizeof(*eurus_cmd_get_channel_info)) {
1122 + err = -EINVAL;
1123 + goto done;
1126 + if (response_status)
1127 + *response_status = PS3_EURUS_CMD_OK;
1129 + if (response_length && response) {
1130 + *response_length = sizeof(*eurus_cmd_get_channel_info);
1131 + eurus_cmd_get_channel_info = (struct ps3_eurus_cmd_get_channel_info *) response;
1132 + memset(eurus_cmd_get_channel_info, 0, sizeof(*eurus_cmd_get_channel_info));
1133 + eurus_cmd_get_channel_info->channel_info = jd->channel_info >> 48;
1136 + err = 0;
1138 + goto done;
1141 + pkt_hdr = (struct ps3_jupiter_pkt_hdr *) jd->cmd_buf;
1142 + memset(pkt_hdr, 0, sizeof(*pkt_hdr));
1143 + pkt_hdr->unknown1 = 1;
1144 + pkt_hdr->unknown2 = 1;
1145 + pkt_hdr->type = PS3_JUPITER_PKT_CMD;
1147 + cmd_hdr = (struct ps3_jupiter_cmd_hdr *) (pkt_hdr + 1);
1148 + memset(cmd_hdr, 0, sizeof(*cmd_hdr));
1149 + jd->cmd_tag++;
1150 + cmd_hdr->unknown1 = 0;
1151 + cmd_hdr->unknown2 = cpu_to_le16(1);
1152 + cmd_hdr->tag = cpu_to_le16(jd->cmd_tag);
1154 + eurus_cmd_hdr = (struct ps3_eurus_cmd_hdr *) (cmd_hdr + 1);
1155 + memset(eurus_cmd_hdr, 0, sizeof(*eurus_cmd_hdr));
1156 + jd->eurus_cmd = cmd;
1157 + eurus_cmd_hdr->id = cpu_to_le16(cmd);
1158 + jd->eurus_tag++;
1159 + eurus_cmd_hdr->tag = cpu_to_le16(jd->eurus_tag);
1160 + eurus_cmd_hdr->status = cpu_to_le16(0xa);
1161 + eurus_cmd_hdr->payload_length = cpu_to_le16(payload_length);
1163 + if (payload_length)
1164 + memcpy(eurus_cmd_hdr + 1, payload, payload_length);
1166 + init_completion(&jd->cmd_done_comp);
1168 + usb_fill_int_urb(jd->cmd_urb, udev, usb_sndintpipe(udev, PS3_JUPITER_EP),
1169 + jd->cmd_buf, sizeof(*pkt_hdr) + sizeof(*cmd_hdr) + sizeof(*eurus_cmd_hdr) + payload_length,
1170 + ps3_jupiter_cmd_urb_complete, jd, 1);
1172 + err = usb_submit_urb(jd->cmd_urb, GFP_KERNEL);
1173 + if (err) {
1174 + dev_err(&udev->dev, "could not submit command URB (%d)\n", err);
1175 + goto done;
1178 + err = wait_for_completion_timeout(&jd->cmd_done_comp, HZ);
1179 + if (!err) {
1180 + err = -ETIMEDOUT;
1181 + goto done;
1184 + err = jd->cmd_err;
1185 + if (!err) {
1186 + status = le16_to_cpu(eurus_cmd_hdr->status);
1188 + if (response_status)
1189 + *response_status = status;
1191 + if (response_length && response) {
1192 + *response_length = le16_to_cpu(eurus_cmd_hdr->payload_length);
1193 + memcpy(response, eurus_cmd_hdr + 1, *response_length);
1196 + if (status != PS3_EURUS_CMD_OK)
1197 + dev_err(&udev->dev, "EURUS command 0x%04x status (0x%04x)\n", cmd, status);
1200 +done:
1202 + if (err)
1203 + dev_err(&udev->dev, "EURUS command 0x%04x failed (%d)\n", cmd, err);
1205 + jd->cmd_busy = 0;
1207 + return err;
1211 + * _ps3_jupiter_exec_eurus_cmd
1212 + */
1213 +int ps3_jupiter_exec_eurus_cmd(enum ps3_eurus_cmd_id cmd,
1214 + void *payload, unsigned int payload_length,
1215 + unsigned int *response_status,
1216 + unsigned int *response_length, void *response)
1218 + struct ps3_jupiter_dev *jd = ps3jd;
1219 + int err;
1221 + if (!jd || !jd->dev_ready)
1222 + return -ENODEV;
1224 + err = _ps3_jupiter_exec_eurus_cmd(jd, cmd, payload, payload_length,
1225 + response_status, response_length, response);
1227 + return err;
1230 +EXPORT_SYMBOL_GPL(ps3_jupiter_exec_eurus_cmd);
1233 + * ps3_jupiter_create_event_worker
1234 + */
1235 +static int ps3_jupiter_create_event_worker(struct ps3_jupiter_dev *jd)
1237 + jd->event_queue = create_singlethread_workqueue("ps3_jupiter_event");
1238 + if (!jd->event_queue)
1239 + return -ENOMEM;
1241 + INIT_DELAYED_WORK(&jd->event_work, ps3_jupiter_event_worker);
1243 + return 0;
1247 + * ps3_jupiter_destroy_event_worker
1248 + */
1249 +static void ps3_jupiter_destroy_event_worker(struct ps3_jupiter_dev *jd)
1251 + if (jd->event_queue) {
1252 + cancel_delayed_work(&jd->event_work);
1253 + flush_workqueue(jd->event_queue);
1254 + destroy_workqueue(jd->event_queue);
1255 + jd->event_queue = NULL;
1260 + * ps3_jupiter_free_event_list
1261 + */
1262 +static void ps3_jupiter_free_event_list(struct ps3_jupiter_dev *jd)
1264 + struct ps3_jupiter_list_event *event, *tmp;
1266 + list_for_each_entry_safe(event, tmp, &jd->event_list, list) {
1267 + list_del(&event->list);
1268 + kfree(event);
1273 + * ps3_jupiter_alloc_urbs
1274 + */
1275 +static int ps3_jupiter_alloc_urbs(struct ps3_jupiter_dev *jd)
1277 + struct usb_device *udev = jd->udev;
1279 + jd->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
1280 + if (!jd->irq_urb)
1281 + return -ENOMEM;
1283 + jd->irq_buf = usb_alloc_coherent(udev, PS3_JUPITER_IRQ_BUFSIZE,
1284 + GFP_KERNEL, &jd->irq_urb->transfer_dma);
1285 + if (!jd->irq_buf)
1286 + return -ENOMEM;
1288 + usb_fill_int_urb(jd->irq_urb, udev, usb_rcvintpipe(udev, PS3_JUPITER_EP),
1289 + jd->irq_buf, PS3_JUPITER_IRQ_BUFSIZE, ps3_jupiter_irq_urb_complete, jd, 1);
1290 + jd->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1292 + jd->cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
1293 + if (!jd->cmd_urb)
1294 + return -ENOMEM;
1296 + jd->cmd_buf = usb_alloc_coherent(udev, PS3_JUPITER_CMD_BUFSIZE,
1297 + GFP_KERNEL, &jd->cmd_urb->transfer_dma);
1298 + if (!jd->cmd_buf)
1299 + return -ENOMEM;
1301 + usb_fill_int_urb(jd->cmd_urb, udev, usb_sndintpipe(udev, PS3_JUPITER_EP),
1302 + jd->cmd_buf, PS3_JUPITER_CMD_BUFSIZE, ps3_jupiter_cmd_urb_complete, jd, 1);
1303 + jd->cmd_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1305 + return 0;
1309 + * ps3_jupiter_free_urbs
1310 + */
1311 +static void ps3_jupiter_free_urbs(struct ps3_jupiter_dev *jd)
1313 + struct usb_device *udev = jd->udev;
1315 + if (jd->irq_urb) {
1316 + usb_kill_urb(jd->irq_urb);
1318 + if (jd->irq_buf)
1319 + usb_free_coherent(udev, PS3_JUPITER_IRQ_BUFSIZE,
1320 + jd->irq_buf, jd->irq_urb->transfer_dma);
1322 + usb_free_urb(jd->irq_urb);
1325 + if (jd->cmd_urb) {
1326 + usb_kill_urb(jd->cmd_urb);
1328 + if (jd->cmd_buf)
1329 + usb_free_coherent(udev, PS3_JUPITER_CMD_BUFSIZE,
1330 + jd->cmd_buf, jd->cmd_urb->transfer_dma);
1332 + usb_free_urb(jd->cmd_urb);
1337 + * ps3_jupiter_dev_auth
1338 + */
1339 +static int ps3_jupiter_dev_auth(struct ps3_jupiter_dev *jd)
1341 + struct usb_device *udev = jd->udev;
1342 + void *buf;
1343 + int err;
1345 + buf = kmalloc(sizeof(ps3_jupiter_devkey), GFP_KERNEL);
1346 + if (!buf)
1347 + return -ENOMEM;
1349 + memcpy(buf, ps3_jupiter_devkey, sizeof(ps3_jupiter_devkey));
1351 + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
1352 + 0x1, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 0x9, 0x0,
1353 + buf, sizeof(ps3_jupiter_devkey), USB_CTRL_SET_TIMEOUT);
1354 + if (err < 0) {
1355 + dev_dbg(&udev->dev, "could not send device key (%d)\n", err);
1356 + return err;
1359 + kfree(buf);
1361 + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
1362 + 0x0, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, 0x2, 0x0,
1363 + &jd->dev_status, sizeof(jd->dev_status), USB_CTRL_GET_TIMEOUT);
1364 + if (err < 0) {
1365 + dev_dbg(&udev->dev, "could not read device status (%d)\n", err);
1366 + return err;
1369 + dev_info(&udev->dev, "device status (0x%04x)\n", jd->dev_status);
1371 + return 0;
1375 + * ps3_jupiter_event_handler
1376 + */
1377 +static int ps3_jupiter_event_handler(struct notifier_block *n,
1378 + unsigned long val, void *v)
1380 + struct ps3_jupiter_dev *jd = container_of(n, struct ps3_jupiter_dev, event_listener);
1381 + struct usb_device *udev = jd->udev;
1382 + struct ps3_eurus_event *event = v;
1384 + dev_dbg(&udev->dev, "got event (0x%08x 0x%08x 0x%08x 0x%08x 0x%08x)\n",
1385 + event->hdr.type, event->hdr.id, event->hdr.timestamp, event->hdr.payload_length,
1386 + event->hdr.unknown);
1388 + if (event->hdr.type == PS3_EURUS_EVENT_TYPE_0x400) {
1389 + if ((event->hdr.id == 0x8) || (event->hdr.id == 0x10))
1390 + complete(&jd->event_comp);
1393 + return NOTIFY_OK;
1397 + * ps3_jupiter_dev_init
1398 + */
1399 +static int ps3_jupiter_dev_init(struct ps3_jupiter_dev *jd)
1401 + struct usb_device *udev = jd->udev;
1402 + struct ps3_eurus_cmd_0x114f *eurus_cmd_0x114f;
1403 + struct ps3_eurus_cmd_0x116f *eurus_cmd_0x116f;
1404 + struct ps3_eurus_cmd_0x115b *eurus_cmd_0x115b;
1405 + const u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1406 + u8 h;
1407 + struct ps3_eurus_cmd_mcast_addr_filter *eurus_cmd_mcast_addr_filter;
1408 + struct ps3_eurus_cmd_0x110d *eurus_cmd_0x110d;
1409 + struct ps3_eurus_cmd_0x1031 *eurus_cmd_0x1031;
1410 + struct ps3_eurus_cmd_set_mac_addr *eurus_cmd_set_mac_addr;
1411 + struct ps3_eurus_cmd_set_antenna *eurus_cmd_set_antenna;
1412 + struct ps3_eurus_cmd_0x110b *eurus_cmd_0x110b;
1413 + struct ps3_eurus_cmd_0x1109 *eurus_cmd_0x1109;
1414 + struct ps3_eurus_cmd_0x207 *eurus_cmd_0x207;
1415 + struct ps3_eurus_cmd_0x203 *eurus_cmd_0x203;
1416 + struct ps3_eurus_cmd_0x105f *eurus_cmd_0x105f;
1417 + struct ps3_eurus_cmd_get_fw_version *eurus_cmd_get_fw_version;
1418 + unsigned char *buf;
1419 + unsigned int status, response_length;
1420 + int err;
1422 + buf = kmalloc(PS3_JUPITER_CMD_BUFSIZE, GFP_KERNEL);
1423 + if (!buf)
1424 + return -ENOMEM;
1426 + /* state 1 */
1428 + eurus_cmd_0x114f = (struct ps3_eurus_cmd_0x114f *) buf;
1429 + memset(eurus_cmd_0x114f, 0, sizeof(*eurus_cmd_0x114f));
1431 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x114f,
1432 + eurus_cmd_0x114f, sizeof(*eurus_cmd_0x114f), &status, NULL, NULL);
1433 + if (err)
1434 + goto done;
1436 + /* do not check command status here !!! */
1438 + /* state 2 */
1440 + init_completion(&jd->event_comp);
1442 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x1171, NULL, 0, &status, NULL, NULL);
1443 + if (err)
1444 + goto done;
1446 + if (status != PS3_EURUS_CMD_OK) {
1447 + err = -EIO;
1448 + goto done;
1451 + /* state 3 */
1453 + err = wait_for_completion_timeout(&jd->event_comp, HZ);
1454 + if (!err) {
1455 + err = -ETIMEDOUT;
1456 + goto done;
1459 + /* state 4 */
1461 + eurus_cmd_0x116f = (struct ps3_eurus_cmd_0x116f *) buf;
1462 + memset(eurus_cmd_0x116f, 0, sizeof(*eurus_cmd_0x116f));
1463 + eurus_cmd_0x116f->unknown = cpu_to_le32(0x1);
1465 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x116f,
1466 + eurus_cmd_0x116f, sizeof(*eurus_cmd_0x116f), &status, NULL, NULL);
1467 + if (err)
1468 + goto done;
1470 + if (status != PS3_EURUS_CMD_OK) {
1471 + err = -EIO;
1472 + goto done;
1475 + /* state 5 */
1477 + eurus_cmd_0x115b = (struct ps3_eurus_cmd_0x115b *) buf;
1478 + memset(eurus_cmd_0x115b, 0, sizeof(*eurus_cmd_0x115b));
1479 + eurus_cmd_0x115b->unknown1 = cpu_to_le16(0x1);
1480 + eurus_cmd_0x115b->unknown2 = cpu_to_le16(0x0);
1481 + memcpy(eurus_cmd_0x115b->mac_addr, jd->mac_addr, sizeof(jd->mac_addr));
1483 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x115b,
1484 + eurus_cmd_0x115b, sizeof(*eurus_cmd_0x115b), &status, NULL, NULL);
1485 + if (err)
1486 + goto done;
1488 + if (status != PS3_EURUS_CMD_OK) {
1489 + err = -EIO;
1490 + goto done;
1493 + /* state 6 */
1495 + h = ps3_eurus_mcast_addr_hash(bcast_addr);
1497 + eurus_cmd_mcast_addr_filter = (struct ps3_eurus_cmd_mcast_addr_filter *) buf;
1498 + memset(eurus_cmd_mcast_addr_filter, 0, sizeof(*eurus_cmd_mcast_addr_filter));
1499 + eurus_cmd_mcast_addr_filter->word[PS3_EURUS_MCAST_ADDR_HASH2POS(h)] |=
1500 + cpu_to_le32(PS3_EURUS_MCAST_ADDR_HASH2VAL(h));
1502 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_SET_MCAST_ADDR_FILTER,
1503 + eurus_cmd_mcast_addr_filter, sizeof(*eurus_cmd_mcast_addr_filter), &status, NULL, NULL);
1504 + if (err)
1505 + goto done;
1507 + if (status != PS3_EURUS_CMD_OK) {
1508 + err = -EIO;
1509 + goto done;
1512 + /* state 7 */
1514 + eurus_cmd_0x110d = (struct ps3_eurus_cmd_0x110d *) buf;
1515 + memset(eurus_cmd_0x110d, 0, sizeof(*eurus_cmd_0x110d));
1516 + eurus_cmd_0x110d->unknown1 = cpu_to_le32(0xffffffff);
1517 + eurus_cmd_0x110d->unknown2 = cpu_to_le32(0xffffffff);
1518 + eurus_cmd_0x110d->unknown3 = cpu_to_le32(0xffffffff);
1519 + eurus_cmd_0x110d->unknown4 = cpu_to_le32(0xffffffff);
1520 + eurus_cmd_0x110d->unknown5 = cpu_to_le32(0xffffffff);
1521 + eurus_cmd_0x110d->unknown6 = cpu_to_le32(0xffffffff);
1522 + eurus_cmd_0x110d->unknown7 = cpu_to_le32(0xffffffff);
1524 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x110d,
1525 + eurus_cmd_0x110d, sizeof(*eurus_cmd_0x110d), &status, NULL, NULL);
1526 + if (err)
1527 + goto done;
1529 + if (status != PS3_EURUS_CMD_OK) {
1530 + err = -EIO;
1531 + goto done;
1534 + /* state 8 */
1536 + eurus_cmd_0x1031 = (struct ps3_eurus_cmd_0x1031 *) buf;
1537 + memset(eurus_cmd_0x1031, 0, sizeof(*eurus_cmd_0x1031));
1538 + eurus_cmd_0x1031->unknown1 = 0x0;
1539 + eurus_cmd_0x1031->unknown2 = 0x0;
1541 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x1031,
1542 + eurus_cmd_0x1031, sizeof(*eurus_cmd_0x1031), &status, NULL, NULL);
1543 + if (err)
1544 + goto done;
1546 + if (status != PS3_EURUS_CMD_OK) {
1547 + err = -EIO;
1548 + goto done;
1551 + /* state 9 */
1553 + eurus_cmd_set_mac_addr = (struct ps3_eurus_cmd_set_mac_addr *) buf;
1554 + memset(eurus_cmd_set_mac_addr, 0, sizeof(*eurus_cmd_set_mac_addr));
1555 + memcpy(eurus_cmd_set_mac_addr->mac_addr, jd->mac_addr, sizeof(jd->mac_addr));
1557 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_SET_MAC_ADDR,
1558 + eurus_cmd_set_mac_addr, sizeof(*eurus_cmd_set_mac_addr), &status, NULL, NULL);
1559 + if (err)
1560 + goto done;
1562 + if (status != PS3_EURUS_CMD_OK) {
1563 + err = -EIO;
1564 + goto done;
1567 + /* state 10 */
1569 + eurus_cmd_set_antenna = (struct ps3_eurus_cmd_set_antenna *) buf;
1570 + memset(eurus_cmd_set_antenna, 0, sizeof(*eurus_cmd_set_antenna));
1572 + if (((jd->channel_info >> 40) & 0xff) == 0x1) {
1573 + eurus_cmd_set_antenna->unknown1 = 0x1;
1574 + eurus_cmd_set_antenna->unknown2 = 0x0;
1575 + } else if (((jd->channel_info >> 40) & 0xff) == 0x2) {
1576 + eurus_cmd_set_antenna->unknown1 = 0x1;
1577 + eurus_cmd_set_antenna->unknown2 = 0x1;
1578 + } else {
1579 + eurus_cmd_set_antenna->unknown1 = 0x2;
1580 + eurus_cmd_set_antenna->unknown2 = 0x2;
1583 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_SET_ANTENNA,
1584 + eurus_cmd_set_antenna, sizeof(*eurus_cmd_set_antenna), &status, NULL, NULL);
1585 + if (err)
1586 + goto done;
1588 + if (status != PS3_EURUS_CMD_OK) {
1589 + err = -EIO;
1590 + goto done;
1593 + /* state 11 */
1595 + eurus_cmd_0x110b = (struct ps3_eurus_cmd_0x110b *) buf;
1596 + memset(eurus_cmd_0x110b, 0, sizeof(*eurus_cmd_0x110b));
1597 + eurus_cmd_0x110b->unknown1 = cpu_to_le32(0x1);
1598 + eurus_cmd_0x110b->unknown2 = cpu_to_le32(0x200000);
1600 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x110b,
1601 + eurus_cmd_0x110b, sizeof(*eurus_cmd_0x110b), &status, NULL, NULL);
1602 + if (err)
1603 + goto done;
1605 + if (status != PS3_EURUS_CMD_OK) {
1606 + err = -EIO;
1607 + goto done;
1610 + /* state 12 */
1612 + eurus_cmd_0x1109 = (struct ps3_eurus_cmd_0x1109 *) buf;
1613 + ps3_eurus_make_cmd_0x1109(eurus_cmd_0x1109, 0x1, 0x0, 0x2715, 0x9, 0x12);
1615 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x1109,
1616 + eurus_cmd_0x1109, sizeof(*eurus_cmd_0x1109), &status, NULL, NULL);
1617 + if (err)
1618 + goto done;
1620 + if (status != PS3_EURUS_CMD_OK) {
1621 + err = -EIO;
1622 + goto done;
1625 + /* state 13 */
1627 + eurus_cmd_0x207 = (struct ps3_eurus_cmd_0x207 *) buf;
1628 + memset(eurus_cmd_0x207, 0, sizeof(*eurus_cmd_0x207));
1629 + eurus_cmd_0x207->unknown = cpu_to_le32(0x1);
1631 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x207,
1632 + eurus_cmd_0x207, sizeof(*eurus_cmd_0x207), &status, NULL, NULL);
1633 + if (err)
1634 + goto done;
1636 + if (status != PS3_EURUS_CMD_OK) {
1637 + err = -EIO;
1638 + goto done;
1641 + /* state 14 */
1643 + eurus_cmd_0x203 = (struct ps3_eurus_cmd_0x203 *) buf;
1644 + memset(eurus_cmd_0x203, 0, sizeof(*eurus_cmd_0x203));
1645 + eurus_cmd_0x203->unknown = cpu_to_le32(0x1);
1647 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x203,
1648 + eurus_cmd_0x203, sizeof(*eurus_cmd_0x203), &status, NULL, NULL);
1649 + if (err)
1650 + goto done;
1652 + if (status != PS3_EURUS_CMD_OK) {
1653 + err = -EIO;
1654 + goto done;
1657 + /* state 15 */
1659 + eurus_cmd_0x105f = (struct ps3_eurus_cmd_0x105f *) buf;
1660 + memset(eurus_cmd_0x105f, 0, sizeof(*eurus_cmd_0x105f));
1661 + eurus_cmd_0x105f->channel_info = cpu_to_le16(jd->channel_info >> 48);
1662 + memcpy(eurus_cmd_0x105f->mac_addr, jd->mac_addr, sizeof(jd->mac_addr));
1664 + if (((jd->channel_info >> 40) & 0xff) == 0x1) {
1665 + eurus_cmd_0x105f->unknown1 = 0x1;
1666 + eurus_cmd_0x105f->unknown2 = 0x0;
1667 + } else if (((jd->channel_info >> 40) & 0xff) == 0x2) {
1668 + eurus_cmd_0x105f->unknown1 = 0x1;
1669 + eurus_cmd_0x105f->unknown2 = 0x1;
1670 + } else {
1671 + eurus_cmd_0x105f->unknown1 = 0x2;
1672 + eurus_cmd_0x105f->unknown2 = 0x2;
1675 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_0x105f,
1676 + eurus_cmd_0x105f, sizeof(*eurus_cmd_0x105f), &status, NULL, NULL);
1677 + if (err)
1678 + goto done;
1680 + if (status != PS3_EURUS_CMD_OK) {
1681 + err = -EIO;
1682 + goto done;
1685 + /* device is ready now */
1687 + /* read firmware version */
1689 + eurus_cmd_get_fw_version = (struct ps3_eurus_cmd_get_fw_version *) buf;
1690 + memset(eurus_cmd_get_fw_version, 0, sizeof(*eurus_cmd_get_fw_version));
1692 + err = _ps3_jupiter_exec_eurus_cmd(jd, PS3_EURUS_CMD_GET_FW_VERSION,
1693 + eurus_cmd_get_fw_version, sizeof(*eurus_cmd_get_fw_version),
1694 + &status, &response_length, eurus_cmd_get_fw_version);
1695 + if (err)
1696 + goto done;
1698 + if (status != PS3_EURUS_CMD_OK) {
1699 + err = -EIO;
1700 + goto done;
1703 + dev_info(&udev->dev, "firmware version: %s\n", (char *) eurus_cmd_get_fw_version->version);
1705 + err = 0;
1707 +done:
1709 + kfree(buf);
1711 + return err;
1715 + * ps3_jupiter_probe
1716 + */
1717 +static int ps3_jupiter_probe(struct usb_interface *interface,
1718 + const struct usb_device_id *id)
1720 + struct usb_device *udev = interface_to_usbdev(interface);
1721 + struct ps3_jupiter_dev *jd;
1722 + u64 v1, v2;
1723 + int err;
1725 + if (ps3jd) {
1726 + dev_err(&udev->dev, "only one device is supported\n");
1727 + return -EBUSY;
1730 + ps3jd = jd = kzalloc(sizeof(struct ps3_jupiter_dev), GFP_KERNEL);
1731 + if (!jd)
1732 + return -ENOMEM;
1734 + jd->udev = usb_get_dev(udev);
1735 + usb_set_intfdata(interface, jd);
1737 + spin_lock_init(&jd->cmd_lock);
1739 + BLOCKING_INIT_NOTIFIER_HEAD(&jd->event_listeners);
1740 + INIT_LIST_HEAD(&jd->event_list);
1741 + spin_lock_init(&jd->event_list_lock);
1743 + init_completion(&jd->event_comp);
1745 + jd->event_listener.notifier_call = ps3_jupiter_event_handler;
1747 + err = _ps3_jupiter_register_event_listener(jd, &jd->event_listener);
1748 + if (err) {
1749 + dev_err(&udev->dev, "could not register event listener (%d)\n", err);
1750 + goto fail;
1753 + err = ps3_jupiter_create_event_worker(jd);
1754 + if (err) {
1755 + dev_err(&udev->dev, "could not create event work queue (%d)\n", err);
1756 + goto fail;
1759 + err = ps3_jupiter_alloc_urbs(jd);
1760 + if (err) {
1761 + dev_err(&udev->dev, "could not allocate URBs (%d)\n", err);
1762 + goto fail;
1765 + err = usb_submit_urb(jd->irq_urb, GFP_KERNEL);
1766 + if (err) {
1767 + dev_err(&udev->dev, "could not submit IRQ URB (%d)\n", err);
1768 + goto fail;
1771 + err = ps3_jupiter_dev_auth(jd);
1772 + if (err) {
1773 + dev_err(&udev->dev, "could not authenticate device (%d)\n", err);
1774 + goto fail;
1777 + /* get MAC address */
1779 + err = lv1_net_control(LV1_SB_BUS_ID, LV1_GELIC_DEV_ID,
1780 + LV1_GET_MAC_ADDRESS, 0, 0, 0, &v1, &v2);
1781 + if (err) {
1782 + dev_err(&udev->dev, "could not get MAC address (%d)\n", err);
1783 + err = -ENODEV;
1784 + goto fail;
1787 + v1 <<= 16;
1789 + if (!is_valid_ether_addr((unsigned char *) &v1)) {
1790 + dev_err(&udev->dev, "got invalid MAC address\n");
1791 + err = -ENODEV;
1792 + goto fail;
1795 + memcpy(jd->mac_addr, &v1, ETH_ALEN);
1797 + dev_info(&udev->dev, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
1798 + jd->mac_addr[0], jd->mac_addr[1], jd->mac_addr[2],
1799 + jd->mac_addr[3], jd->mac_addr[4], jd->mac_addr[5]);
1801 + /* get channel info */
1803 + err = lv1_net_control(LV1_SB_BUS_ID, LV1_GELIC_DEV_ID,
1804 + LV1_GET_CHANNEL_INFO, 0, 0, 0, &v1, &v2);
1805 + if (err) {
1806 + /* don't quit here and try to recover later */
1807 + dev_err(&udev->dev, "could not get channel info (%d)\n", err);
1810 + if (err)
1811 + jd->channel_info = (0x7ffull << 48);
1812 + else
1813 + jd->channel_info = v1;
1815 + dev_info(&udev->dev, "channel info: %016llx\n", jd->channel_info);
1817 + err = ps3_jupiter_dev_init(jd);
1818 + if (err) {
1819 + dev_err(&udev->dev, "could not initialize device (%d)\n", err);
1820 + goto fail;
1823 + jd->dev_ready = 1;
1825 + return 0;
1827 +fail:
1829 + ps3_jupiter_free_urbs(jd);
1831 + ps3_jupiter_destroy_event_worker(jd);
1833 + ps3_jupiter_free_event_list(jd);
1835 + usb_set_intfdata(interface, NULL);
1836 + usb_put_dev(udev);
1838 + kfree(jd);
1839 + ps3jd = NULL;
1841 + return err;
1845 + * ps3_jupiter_disconnect
1846 + */
1847 +static void ps3_jupiter_disconnect(struct usb_interface *interface)
1849 + struct ps3_jupiter_dev *jd = usb_get_intfdata(interface);
1850 + struct usb_device *udev = jd->udev;
1852 + jd->dev_ready = 0;
1854 + ps3_jupiter_free_urbs(jd);
1856 + ps3_jupiter_destroy_event_worker(jd);
1858 + ps3_jupiter_free_event_list(jd);
1860 + usb_set_intfdata(interface, NULL);
1861 + usb_put_dev(udev);
1863 + kfree(jd);
1864 + ps3jd = NULL;
1867 +#ifdef CONFIG_PM
1869 + * ps3_jupiter_suspend
1870 + */
1871 +static int ps3_jupiter_suspend(struct usb_interface *interface, pm_message_t state)
1873 + /*XXX: implement */
1875 + return 0;
1879 + * ps3_jupiter_resume
1880 + */
1881 +static int ps3_jupiter_resume(struct usb_interface *interface)
1883 + /*XXX: implement */
1885 + return 0;
1887 +#endif /* CONFIG_PM */
1889 +static struct usb_device_id ps3_jupiter_devtab[] = {
1891 + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
1892 + .idVendor = 0x054c,
1893 + .idProduct = 0x036f,
1894 + .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
1895 + .bInterfaceSubClass = 2,
1896 + .bInterfaceProtocol = 1
1897 + },
1898 + { }
1901 +static struct usb_driver ps3_jupiter_drv = {
1902 + .name = KBUILD_MODNAME,
1903 + .id_table = ps3_jupiter_devtab,
1904 + .probe = ps3_jupiter_probe,
1905 + .disconnect = ps3_jupiter_disconnect,
1906 +#ifdef CONFIG_PM
1907 + .suspend = ps3_jupiter_suspend,
1908 + .resume = ps3_jupiter_resume,
1909 +#endif /* CONFIG_PM */
1913 + * ps3_jupiter_init
1914 + */
1915 +static int __init ps3_jupiter_init(void)
1917 + return usb_register(&ps3_jupiter_drv);
1921 + * ps3_jupiter_exit
1922 + */
1923 +static void __exit ps3_jupiter_exit(void)
1925 + usb_deregister(&ps3_jupiter_drv);
1928 +module_init(ps3_jupiter_init);
1929 +module_exit(ps3_jupiter_exit);
1931 +MODULE_SUPPORTED_DEVICE("PS3 Jupiter");
1932 +MODULE_DEVICE_TABLE(usb, ps3_jupiter_devtab);
1933 +MODULE_DESCRIPTION("PS3 Jupiter");
1934 +MODULE_AUTHOR("glevand");
1935 +MODULE_LICENSE("GPL");
1936 --- /dev/null 2012-11-01 00:09:58.397610712 -0800
1937 +++ b/drivers/net/wireless/ps3jupiter/ps3_jupiter_sta.c 2012-11-01 03:22:36.000000000 -0800
1938 @@ -0,0 +1,2934 @@
1941 + * PS3 Jupiter STA
1943 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
1944 + * All rights reserved.
1946 + * This program is free software; you can redistribute it and/or modify it
1947 + * under the terms of the GNU General Public License as published
1948 + * by the Free Software Foundation; version 2 of the License.
1950 + * This program is distributed in the hope that it will be useful, but
1951 + * WITHOUT ANY WARRANTY; without even the implied warranty of
1952 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1953 + * General Public License for more details.
1955 + * You should have received a copy of the GNU General Public License along
1956 + * with this program; if not, write to the Free Software Foundation, Inc.,
1957 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1958 + */
1960 +#include <linux/module.h>
1961 +#include <linux/kernel.h>
1962 +#include <linux/init.h>
1963 +#include <linux/slab.h>
1964 +#include <linux/usb.h>
1965 +#include <linux/interrupt.h>
1966 +#include <linux/notifier.h>
1968 +#include <linux/etherdevice.h>
1969 +#include <linux/ethtool.h>
1970 +#include <linux/if_arp.h>
1971 +#include <linux/ieee80211.h>
1972 +#include <net/iw_handler.h>
1974 +#include "ps3_eurus.h"
1975 +#include "ps3_jupiter.h"
1977 +#define PS3_JUPITER_STA_CMD_BUFSIZE 2048
1979 +#define PS3_JUPITER_STA_IFACE 0x4
1980 +#define PS3_JUPITER_STA_EP 0x6
1982 +#define PS3_JUPITER_STA_WEP_KEYS 4
1984 +#define PS3_JUPITER_STA_WPA_PSK_LENGTH 32
1986 +#define PS3_JUPITER_STA_RX_URBS 4
1987 +#define PS3_JUPITER_STA_RX_BUFSIZE 0x620
1989 +#define PS3_JUPITER_STA_TX_URBS 16
1991 +#define PS3_JUPITER_STA_CHANNEL_DWELL 0x64
1993 +#define PS3_JUPITER_STA_SCAN_VALID_TIME_SEC 60
1995 +enum ps3_jupiter_sta_status {
1996 + PS3_JUPITER_STA_READY = 0,
1999 +enum ps3_jupiter_sta_scan_status {
2000 + PS3_JUPITER_STA_SCAN_INVALID = 0,
2001 + PS3_JUPITER_STA_SCAN_IN_PROGRESS,
2002 + PS3_JUPITER_STA_SCAN_OK
2005 +enum ps3_jupiter_sta_assoc_status {
2006 + PS3_JUPITER_STA_ASSOC_INVALID = 0,
2007 + PS3_JUPITER_STA_ASSOC_IN_PROGRESS,
2008 + PS3_JUPITER_STA_ASSOC_OK
2011 +enum ps3_jupiter_sta_config_bits {
2012 + PS3_JUPITER_STA_CONFIG_ESSID_SET = 0,
2013 + PS3_JUPITER_STA_CONFIG_BSSID_SET,
2014 + PS3_JUPITER_STA_CONFIG_CHANNEL_SET,
2015 + PS3_JUPITER_STA_CONFIG_WPA_PSK_SET
2018 +enum ps3_jupiter_sta_bss_type {
2019 + PS3_JUPITER_STA_BSS_TYPE_INFRA = 0,
2020 + PS3_JUPITER_STA_BSS_TYPE_ADHOC,
2023 +enum ps3_jupiter_sta_opmode {
2024 + PS3_JUPITER_STA_OPMODE_11B = 0,
2025 + PS3_JUPITER_STA_OPMODE_11G,
2026 + PS3_JUPITER_STA_OPMODE_11BG
2029 +enum ps3_jupiter_sta_auth_mode {
2030 + PS3_JUPITER_STA_AUTH_OPEN = 0,
2031 + PS3_JUPITER_STA_AUTH_SHARED_KEY
2034 +enum ps3_jupiter_sta_wpa_mode {
2035 + PS3_JUPITER_STA_WPA_MODE_NONE = 0,
2036 + PS3_JUPITER_STA_WPA_MODE_WPA,
2037 + PS3_JUPITER_STA_WPA_MODE_WPA2
2040 +enum ps3_jupiter_sta_cipher_mode {
2041 + PS3_JUPITER_STA_CIPHER_NONE = 0,
2042 + PS3_JUPITER_STA_CIPHER_WEP,
2043 + PS3_JUPITER_STA_CIPHER_TKIP,
2044 + PS3_JUPITER_STA_CIPHER_AES
2047 +struct ps3_jupiter_sta_scan_result {
2048 + struct list_head list;
2050 + u8 bssid[6];
2051 + u16 capability;
2052 + u8 rssi;
2054 + u8 *essid_ie;
2055 + u8 *ds_param_set_ie;
2056 + u8 *supp_rates_ie;
2057 + u8 *ext_supp_rates_ie;
2058 + u8 *rsn_ie;
2059 + u8 *wpa_ie;
2061 + unsigned int ie_length;
2062 + u8 ie[0];
2065 +struct ps3_jupiter_sta_dev {
2066 + struct net_device *netdev;
2068 + struct usb_device *udev;
2070 + spinlock_t lock;
2072 + unsigned long status;
2074 + struct iw_public_data wireless_data;
2075 + struct iw_statistics wireless_stat;
2077 + struct notifier_block event_listener;
2079 + u16 channel_info;
2081 + struct mutex scan_lock;
2082 + struct list_head scan_result_list;
2083 + enum ps3_jupiter_sta_scan_status scan_status;
2084 + struct completion scan_done_comp;
2085 + unsigned long scan_expires;
2087 + unsigned long config_status;
2089 + enum ps3_jupiter_sta_bss_type bss_type;
2091 + enum ps3_jupiter_sta_opmode opmode;
2093 + enum ps3_jupiter_sta_auth_mode auth_mode;
2095 + enum ps3_jupiter_sta_wpa_mode wpa_mode;
2096 + enum ps3_jupiter_sta_cipher_mode group_cipher_mode;
2097 + enum ps3_jupiter_sta_cipher_mode pairwise_cipher_mode;
2099 + u8 essid[IW_ESSID_MAX_SIZE];
2100 + unsigned int essid_length;
2102 + u8 desired_bssid[ETH_ALEN];
2103 + u8 bssid[ETH_ALEN];
2105 + u8 channel;
2107 + unsigned long key_config_status;
2108 + u8 key[PS3_JUPITER_STA_WEP_KEYS][IW_ENCODING_TOKEN_MAX];
2109 + unsigned int key_length[PS3_JUPITER_STA_WEP_KEYS];
2110 + unsigned int curr_key_index;
2112 + u8 psk[PS3_JUPITER_STA_WPA_PSK_LENGTH];
2114 + struct mutex assoc_lock;
2115 + struct workqueue_struct *assoc_queue;
2116 + struct delayed_work assoc_work;
2117 + enum ps3_jupiter_sta_assoc_status assoc_status;
2118 + struct completion assoc_done_comp;
2120 + struct usb_anchor rx_urb_anchor;
2121 + struct sk_buff_head rx_skb_queue;
2122 + struct tasklet_struct rx_tasklet;
2124 + struct usb_anchor tx_urb_anchor;
2125 + atomic_t tx_submitted_urbs;
2128 +static int max_txurbs = PS3_JUPITER_STA_TX_URBS;
2129 +module_param(max_txurbs, int, S_IRUGO);
2130 +MODULE_PARM_DESC(max_txurbs, "Maximum number of Tx URBs");
2132 +static const int ps3_jupiter_sta_channel_freq[] = {
2133 + 2412,
2134 + 2417,
2135 + 2422,
2136 + 2427,
2137 + 2432,
2138 + 2437,
2139 + 2442,
2140 + 2447,
2141 + 2452,
2142 + 2457,
2143 + 2462,
2144 + 2467,
2145 + 2472,
2146 + 2484
2149 +static const int ps3_jupiter_sta_bitrate[] = {
2150 + 1000000,
2151 + 2000000,
2152 + 5500000,
2153 + 11000000,
2154 + 6000000,
2155 + 9000000,
2156 + 12000000,
2157 + 18000000,
2158 + 24000000,
2159 + 36000000,
2160 + 48000000,
2161 + 54000000
2164 +static void ps3_jupiter_sta_free_scan_results(struct ps3_jupiter_sta_dev *jstad);
2166 +static int ps3_jupiter_sta_start_scan(struct ps3_jupiter_sta_dev *jstad,
2167 + u8 *essid, size_t essid_length, u16 channels, u8 active, u16 channel_dwell);
2169 +static char *ps3_jupiter_sta_translate_scan_result(struct ps3_jupiter_sta_dev *jstad,
2170 + struct ps3_jupiter_sta_scan_result *scan_result,
2171 + struct iw_request_info *info, char *stream, char *ends);
2173 +static void ps3_jupiter_sta_start_assoc(struct ps3_jupiter_sta_dev *jstad);
2175 +static int ps3_jupiter_sta_disassoc(struct ps3_jupiter_sta_dev *jstad);
2177 +static void ps3_jupiter_sta_reset_state(struct ps3_jupiter_sta_dev *jstad);
2179 +static int ps3_jupiter_sta_prepare_rx_urb(struct ps3_jupiter_sta_dev *jstad,
2180 + struct urb *urb);
2182 +static void ps3_jupiter_sta_purge_rx_skb_queue(struct ps3_jupiter_sta_dev *jstad);
2184 +static void ps3_jupiter_sta_free_tx_urbs(struct ps3_jupiter_sta_dev *jstad);
2186 +static int ps3_jupiter_sta_tx_skb(struct ps3_jupiter_sta_dev *jstad, struct sk_buff *skb);
2189 + * ps3_jupiter_sta_freq_to_channel
2190 + */
2191 +static u8 ps3_jupiter_sta_freq_to_channel(u32 freq)
2193 + int i;
2195 + for (i = 0; i < ARRAY_SIZE(ps3_jupiter_sta_channel_freq); i++) {
2196 + if (ps3_jupiter_sta_channel_freq[i] == freq)
2197 + return (i + 1);
2200 + return 0;
2204 + * ps3_jupiter_sta_send_iw_ap_event
2205 + */
2206 +static void ps3_jupiter_sta_send_iw_ap_event(struct ps3_jupiter_sta_dev *jstad, u8 *bssid)
2208 + union iwreq_data iwrd;
2210 + memset(&iwrd, 0, sizeof(iwrd));
2212 + if (bssid)
2213 + memcpy(iwrd.ap_addr.sa_data, bssid, ETH_ALEN);
2215 + iwrd.ap_addr.sa_family = ARPHRD_ETHER;
2217 + wireless_send_event(jstad->netdev, SIOCGIWAP, &iwrd, NULL);
2221 + * ps3_jupiter_sta_get_name
2222 + */
2223 +static int ps3_jupiter_sta_get_name(struct net_device *netdev,
2224 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2226 + strcpy(wrqu->name, "IEEE 802.11bg");
2228 + return 0;
2232 + * ps3_jupiter_sta_get_nick
2233 + */
2234 +static int ps3_jupiter_sta_get_nick(struct net_device *netdev,
2235 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2237 + strcpy(extra, "ps3_jupiter_sta");
2238 + wrqu->data.length = strlen(extra);
2239 + wrqu->data.flags = 1;
2241 + return 0;
2245 + * ps3_jupiter_sta_get_range
2246 + */
2247 +static int ps3_jupiter_sta_get_range(struct net_device *netdev,
2248 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2250 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2251 + struct iw_point *point = &wrqu->data;
2252 + struct iw_range *range = (struct iw_range *) extra;
2253 + unsigned int i, chan;
2255 + point->length = sizeof(struct iw_range);
2256 + memset(range, 0, sizeof(struct iw_range));
2258 + range->we_version_compiled = WIRELESS_EXT;
2259 + range->we_version_source = 22;
2261 + for (i = 0, chan = 0;
2262 + (i < ARRAY_SIZE(ps3_jupiter_sta_channel_freq)) && (chan < IW_MAX_FREQUENCIES); i++) {
2263 + if (jstad->channel_info & (1 << i)) {
2264 + range->freq[chan].i = i + 1;
2265 + range->freq[chan].m = ps3_jupiter_sta_channel_freq[i];
2266 + range->freq[chan].e = 6;
2267 + chan++;
2271 + range->num_frequency = chan;
2272 + range->old_num_frequency = chan;
2273 + range->num_channels = chan;
2274 + range->old_num_channels = chan;
2276 + for (i = 0; i < ARRAY_SIZE(ps3_jupiter_sta_bitrate); i++)
2277 + range->bitrate[i] = ps3_jupiter_sta_bitrate[i];
2278 + range->num_bitrates = i;
2280 + range->max_qual.qual = 100;
2281 + range->max_qual.level = 100;
2282 + range->avg_qual.qual = 50;
2283 + range->avg_qual.level = 50;
2284 + range->sensitivity = 0;
2286 + IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
2287 + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
2288 + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
2290 + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
2291 + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
2292 + IW_ENC_CAPA_4WAY_HANDSHAKE;
2294 + range->encoding_size[0] = 5;
2295 + range->encoding_size[1] = 13;
2296 + range->encoding_size[2] = 32;
2297 + range->num_encoding_sizes = 3;
2298 + range->max_encoding_tokens = 4;
2300 + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_CHANNEL;
2302 + return 0;
2306 + * ps3_jupiter_sta_set_mode
2307 + */
2308 +static int ps3_jupiter_sta_set_mode(struct net_device *netdev,
2309 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2311 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2313 + switch (wrqu->mode) {
2314 + case IW_MODE_INFRA:
2315 + jstad->bss_type = PS3_JUPITER_STA_BSS_TYPE_INFRA;
2316 + break;
2317 + case IW_MODE_ADHOC:
2318 + jstad->bss_type = PS3_JUPITER_STA_BSS_TYPE_ADHOC;
2319 + break;
2320 + default:
2321 + return -EOPNOTSUPP;
2324 + return 0;
2328 + * ps3_jupiter_sta_get_mode
2329 + */
2330 +static int ps3_jupiter_sta_get_mode(struct net_device *netdev,
2331 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2333 + wrqu->mode = IW_MODE_INFRA;
2335 + return 0;
2339 + * ps3_jupiter_sta_set_freq
2340 + */
2341 +static int ps3_jupiter_sta_set_freq(struct net_device *netdev,
2342 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2344 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2345 + struct iw_freq *freq = &wrqu->freq;
2346 + __u8 channel;
2347 + unsigned long irq_flags;
2348 + int err;
2350 + spin_lock_irqsave(&jstad->lock, irq_flags);
2352 + if (!freq->m) {
2353 + jstad->channel = 0;
2354 + clear_bit(PS3_JUPITER_STA_CONFIG_CHANNEL_SET, &jstad->config_status);
2355 + } else {
2356 + if (freq->e == 1)
2357 + channel = ps3_jupiter_sta_freq_to_channel(freq->m / 100000);
2358 + else
2359 + channel = freq->m;
2361 + if (!channel || !(jstad->channel_info & (1 << (channel - 1)))) {
2362 + err = -EINVAL;
2363 + goto done;
2366 + jstad->channel = channel;
2367 + set_bit(PS3_JUPITER_STA_CONFIG_CHANNEL_SET, &jstad->config_status);
2370 + err = 0;
2372 +done:
2374 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2376 + return err;
2380 + * ps3_jupiter_sta_get_freq
2381 + */
2382 +static int ps3_jupiter_sta_get_freq(struct net_device *netdev,
2383 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2385 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2386 + struct iw_freq *freq = &wrqu->freq;
2387 + unsigned long irq_flags;
2389 + pr_debug("%s: called\n", __func__);
2391 + spin_lock_irqsave(&jstad->lock, irq_flags);
2393 + if (test_bit(PS3_JUPITER_STA_CONFIG_CHANNEL_SET, &jstad->config_status)) {
2394 + freq->e = 1;
2395 + freq->m = ps3_jupiter_sta_channel_freq[jstad->channel - 1] * 100000;
2396 + } else {
2397 + freq->e = 0;
2398 + freq->m = 0;
2401 + pr_debug("%s: done\n", __func__);
2403 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2405 + return 0;
2409 + * ps3_jupiter_sta_set_scan
2410 + */
2411 +static int ps3_jupiter_sta_set_scan(struct net_device *netdev,
2412 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2414 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2415 + struct iw_scan_req *scan_req;
2416 + u8 *essid = NULL;
2417 + size_t essid_length = 0;
2418 + u16 channels = jstad->channel_info;
2419 + __u8 channel;
2420 + u8 active = 1;
2421 + u16 channel_dwell = PS3_JUPITER_STA_CHANNEL_DWELL;
2422 + int i;
2423 + int err;
2425 + pr_debug("%s: called\n", __func__);
2427 + if (wrqu->data.length == sizeof(*scan_req)) {
2428 + scan_req = (struct iw_scan_req *) extra;
2430 + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
2431 + essid = scan_req->essid;
2432 + essid_length = scan_req->essid_len;
2434 + pr_debug("%s: essid %s\n", __func__, essid);
2437 + if (scan_req->num_channels > 0)
2438 + channels = 0;
2440 + for (i = 0; i < scan_req->num_channels; i++) {
2441 + if (scan_req->channel_list[i].e == 1)
2442 + channel = ps3_jupiter_sta_freq_to_channel(scan_req->channel_list[i].m / 100000);
2443 + else
2444 + channel = scan_req->channel_list[i].m;
2446 + channels |= 1 << (channel - 1);
2449 + pr_debug("%s: channels 0x%04x\n", __func__, channels);
2451 + active = (scan_req->scan_type == IW_SCAN_TYPE_ACTIVE);
2454 + err = ps3_jupiter_sta_start_scan(jstad, essid, essid_length, channels,
2455 + active, channel_dwell);
2457 + pr_debug("%s: done\n", __func__);
2459 + return err;
2463 + * ps3_jupiter_sta_get_scan
2464 + */
2465 +static int ps3_jupiter_sta_get_scan(struct net_device *netdev,
2466 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2468 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2469 + struct ps3_jupiter_sta_scan_result *scan_result;
2470 + char *stream = extra;
2471 + char *ends = stream + wrqu->data.length;
2472 + int err;
2474 + if (mutex_lock_interruptible(&jstad->scan_lock))
2475 + return -EAGAIN;
2477 + if (jstad->scan_status == PS3_JUPITER_STA_SCAN_IN_PROGRESS) {
2478 + err = -EAGAIN;
2479 + goto done;
2480 + } else if (jstad->scan_status == PS3_JUPITER_STA_SCAN_INVALID) {
2481 + err = -ENODEV;
2482 + goto done;
2485 + /* translate scan results */
2487 + list_for_each_entry(scan_result, &jstad->scan_result_list, list) {
2488 + stream = ps3_jupiter_sta_translate_scan_result(jstad, scan_result,
2489 + info, stream, ends);
2491 + if ((ends - stream) <= IW_EV_ADDR_LEN) {
2492 + err = -E2BIG;
2493 + goto done;
2497 + wrqu->data.length = stream - extra;
2498 + wrqu->data.flags = 0;
2500 + err = 0;
2502 +done:
2504 + mutex_unlock(&jstad->scan_lock);
2506 + return err;
2510 + * ps3_jupiter_sta_set_auth
2511 + */
2512 +static int ps3_jupiter_sta_set_auth(struct net_device *netdev,
2513 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2515 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2516 + struct iw_param *param = &wrqu->param;
2517 + unsigned long irq_flags;
2518 + int err = 0;
2520 + spin_lock_irqsave(&jstad->lock, irq_flags);
2522 + switch (param->flags & IW_AUTH_INDEX) {
2523 + case IW_AUTH_WPA_VERSION:
2524 + if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
2525 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_NONE;
2526 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2527 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2528 + } else if (param->value & IW_AUTH_WPA_VERSION_WPA) {
2529 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_WPA;
2530 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_TKIP;
2531 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_TKIP;
2532 + } else if (param->value & IW_AUTH_WPA_VERSION_WPA2) {
2533 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_WPA2;
2534 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_AES;
2535 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_AES;
2537 + break;
2538 + case IW_AUTH_CIPHER_GROUP:
2539 + if (param->value & IW_AUTH_CIPHER_NONE)
2540 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2541 + else if (param->value & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2542 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2543 + else if (param->value & IW_AUTH_CIPHER_TKIP)
2544 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_TKIP;
2545 + else if (param->value & IW_AUTH_CIPHER_CCMP)
2546 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_AES;
2547 + break;
2548 + case IW_AUTH_CIPHER_PAIRWISE:
2549 + if (param->value & IW_AUTH_CIPHER_NONE)
2550 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2551 + else if (param->value & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2552 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2553 + else if (param->value & IW_AUTH_CIPHER_TKIP)
2554 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_TKIP;
2555 + else if (param->value & IW_AUTH_CIPHER_CCMP)
2556 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_AES;
2557 + break;
2558 + case IW_AUTH_80211_AUTH_ALG:
2559 + if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
2560 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_OPEN;
2561 + else if (param->value & IW_AUTH_ALG_SHARED_KEY)
2562 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_SHARED_KEY;
2563 + else
2564 + err = -EINVAL;
2565 + break;
2566 + case IW_AUTH_WPA_ENABLED:
2567 + if (param->value)
2568 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_WPA;
2569 + else
2570 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_NONE;
2571 + break;
2572 + case IW_AUTH_KEY_MGMT:
2573 + if (!(param->value & IW_AUTH_KEY_MGMT_PSK))
2574 + err = -EOPNOTSUPP;
2575 + break;
2576 + default:
2577 + err = -EOPNOTSUPP;
2580 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2582 + return err;
2586 + * ps3_jupiter_sta_get_auth
2587 + */
2588 +static int ps3_jupiter_sta_get_auth(struct net_device *netdev,
2589 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2591 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2592 + struct iw_param *param = &wrqu->param;
2593 + unsigned long irq_flags;
2594 + int err = 0;
2596 + spin_lock_irqsave(&jstad->lock, irq_flags);
2598 + switch (param->flags & IW_AUTH_INDEX) {
2599 + case IW_AUTH_WPA_VERSION:
2600 + switch (jstad->wpa_mode) {
2601 + case PS3_JUPITER_STA_WPA_MODE_WPA:
2602 + param->value |= IW_AUTH_WPA_VERSION_WPA;
2603 + break;
2604 + case PS3_JUPITER_STA_WPA_MODE_WPA2:
2605 + param->value |= IW_AUTH_WPA_VERSION_WPA2;
2606 + break;
2607 + default:
2608 + param->value |= IW_AUTH_WPA_VERSION_DISABLED;
2610 + break;
2611 + case IW_AUTH_80211_AUTH_ALG:
2612 + switch (jstad->auth_mode) {
2613 + case PS3_JUPITER_STA_AUTH_OPEN:
2614 + param->value |= IW_AUTH_ALG_OPEN_SYSTEM;
2615 + break;
2616 + case PS3_JUPITER_STA_AUTH_SHARED_KEY:
2617 + param->value |= IW_AUTH_ALG_SHARED_KEY;
2618 + break;
2620 + break;
2621 + case IW_AUTH_WPA_ENABLED:
2622 + switch (jstad->wpa_mode) {
2623 + case PS3_JUPITER_STA_WPA_MODE_WPA:
2624 + case PS3_JUPITER_STA_WPA_MODE_WPA2:
2625 + param->value = 1;
2626 + break;
2627 + default:
2628 + param->value = 0;
2630 + break;
2631 + default:
2632 + err = -EOPNOTSUPP;
2635 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2637 + return err;
2641 + * ps3_jupiter_sta_set_essid
2642 + */
2643 +static int ps3_jupiter_sta_set_essid(struct net_device *netdev,
2644 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2646 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2647 + unsigned long irq_flags;
2649 + pr_debug("%s: called\n", __func__);
2651 + if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
2652 + return -EINVAL;
2654 + spin_lock_irqsave(&jstad->lock, irq_flags);
2656 + if (wrqu->essid.flags) {
2657 + memcpy(jstad->essid, extra, wrqu->essid.length);
2658 + jstad->essid_length = wrqu->essid.length;
2659 + set_bit(PS3_JUPITER_STA_CONFIG_ESSID_SET, &jstad->config_status);
2661 + pr_debug("%s: essid %s\n", __func__, extra);
2662 + } else {
2663 + clear_bit(PS3_JUPITER_STA_CONFIG_ESSID_SET, &jstad->config_status);
2665 + pr_debug("%s: essid any\n", __func__);
2668 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2670 + ps3_jupiter_sta_start_assoc(jstad);
2672 + pr_debug("%s: done\n", __func__);
2674 + return 0;
2678 + * ps3_jupiter_sta_get_essid
2679 + */
2680 +static int ps3_jupiter_sta_get_essid(struct net_device *netdev,
2681 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2683 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2684 + unsigned long irq_flags;
2686 + spin_lock_irqsave(&jstad->lock, irq_flags);
2688 + if (test_bit(PS3_JUPITER_STA_CONFIG_ESSID_SET, &jstad->config_status)) {
2689 + memcpy(extra, jstad->essid, jstad->essid_length);
2690 + wrqu->essid.length = jstad->essid_length;
2691 + wrqu->essid.flags = 1;
2692 + } else {
2693 + wrqu->essid.flags = 0;
2696 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2698 + return 0;
2702 + * ps3_jupiter_sta_set_ap
2703 + */
2704 +static int ps3_jupiter_sta_set_ap(struct net_device *netdev,
2705 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2707 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2708 + unsigned long irq_flags;
2710 + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
2711 + return -EINVAL;
2713 + spin_lock_irqsave(&jstad->lock, irq_flags);
2715 + if (is_valid_ether_addr(wrqu->ap_addr.sa_data)) {
2716 + memcpy(jstad->desired_bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
2717 + set_bit(PS3_JUPITER_STA_CONFIG_BSSID_SET, &jstad->config_status);
2718 + } else {
2719 + memset(jstad->desired_bssid, 0, ETH_ALEN);
2722 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2724 + return 0;
2728 + * ps3_jupiter_sta_get_ap
2729 + */
2730 +static int ps3_jupiter_sta_get_ap(struct net_device *netdev,
2731 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2733 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2734 + unsigned long irq_flags;
2736 + spin_lock_irqsave(&jstad->lock, irq_flags);
2738 + wrqu->ap_addr.sa_family = ARPHRD_ETHER;
2739 + memcpy(wrqu->ap_addr.sa_data, jstad->desired_bssid, ETH_ALEN);
2741 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2743 + return 0;
2747 + * ps3_jupiter_sta_set_encode
2748 + */
2749 +static int ps3_jupiter_sta_set_encode(struct net_device *netdev,
2750 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2752 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2753 + struct iw_point *enc = &wrqu->encoding;
2754 + __u16 flags = enc->flags & IW_ENCODE_FLAGS;
2755 + int key_index = enc->flags & IW_ENCODE_INDEX;
2756 + int key_index_provided;
2757 + unsigned long irq_flags;
2758 + int err = 0;
2760 + if (key_index > PS3_JUPITER_STA_WEP_KEYS)
2761 + return -EINVAL;
2763 + spin_lock_irqsave(&jstad->lock, irq_flags);
2765 + if (key_index) {
2766 + key_index--;
2767 + key_index_provided = 1;
2768 + } else {
2769 + key_index = jstad->curr_key_index;
2770 + key_index_provided = 0;
2773 + if (flags & IW_ENCODE_NOKEY) {
2774 + if (!(flags & ~IW_ENCODE_NOKEY) && key_index_provided) {
2775 + jstad->curr_key_index = key_index;
2776 + goto done;
2779 + if (flags & IW_ENCODE_DISABLED) {
2780 + if (key_index_provided) {
2781 + clear_bit(key_index, &jstad->key_config_status);
2782 + } else {
2783 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2784 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2785 + jstad->key_config_status = 0;
2789 + if (flags & IW_ENCODE_OPEN)
2790 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_OPEN;
2791 + else if (flags & IW_ENCODE_RESTRICTED)
2792 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_SHARED_KEY;
2793 + } else {
2794 + if (enc->length > IW_ENCODING_TOKEN_MAX) {
2795 + err = -EINVAL;
2796 + goto done;
2799 + memcpy(jstad->key[key_index], extra, enc->length);
2800 + jstad->key_length[key_index] = enc->length;
2801 + set_bit(key_index, &jstad->key_config_status);
2803 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2804 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_WEP;
2807 +done:
2809 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2811 + return err;
2815 + * ps3_jupiter_sta_get_encode
2816 + */
2817 +static int ps3_jupiter_sta_get_encode(struct net_device *netdev,
2818 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2820 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2821 + struct iw_point *enc = &wrqu->encoding;
2822 + int key_index = enc->flags & IW_ENCODE_INDEX;
2823 + int key_index_provided;
2824 + unsigned long irq_flags;
2825 + int err = 0;
2827 + if (key_index > PS3_JUPITER_STA_WEP_KEYS)
2828 + return -EINVAL;
2830 + spin_lock_irqsave(&jstad->lock, irq_flags);
2832 + if (key_index) {
2833 + key_index--;
2834 + key_index_provided = 1;
2835 + } else {
2836 + key_index = jstad->curr_key_index;
2837 + key_index_provided = 0;
2840 + if (jstad->group_cipher_mode == PS3_JUPITER_STA_CIPHER_WEP) {
2841 + switch (jstad->auth_mode) {
2842 + case PS3_JUPITER_STA_AUTH_OPEN:
2843 + enc->flags |= IW_ENCODE_OPEN;
2844 + break;
2845 + case PS3_JUPITER_STA_AUTH_SHARED_KEY:
2846 + enc->flags |= IW_ENCODE_RESTRICTED;
2847 + break;
2849 + } else {
2850 + enc->flags = IW_ENCODE_DISABLED;
2853 + if (test_bit(key_index, &jstad->key_config_status)) {
2854 + if (enc->length < jstad->key_length[key_index]) {
2855 + err = -EINVAL;
2856 + goto done;
2859 + memcpy(extra, jstad->key[key_index], jstad->key_length[key_index]);
2860 + enc->length = jstad->key_length[key_index];
2861 + } else {
2862 + enc->length = 0;
2863 + enc->flags |= IW_ENCODE_NOKEY;
2866 + enc->flags |= (key_index + 1);
2868 +done:
2870 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2872 + return err;
2876 + * ps3_jupiter_sta_set_encodeext
2877 + */
2878 +static int ps3_jupiter_sta_set_encodeext(struct net_device *netdev,
2879 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2881 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2882 + struct iw_point *enc = &wrqu->encoding;
2883 + struct iw_encode_ext *enc_ext = (struct iw_encode_ext *) extra;
2884 + __u16 flags = enc->flags & IW_ENCODE_FLAGS;
2885 + int key_index = enc->flags & IW_ENCODE_INDEX;
2886 + unsigned long irq_flags;
2887 + int err = 0;
2889 + if (key_index > PS3_JUPITER_STA_WEP_KEYS)
2890 + return -EINVAL;
2892 + spin_lock_irqsave(&jstad->lock, irq_flags);
2894 + if (key_index)
2895 + key_index--;
2896 + else
2897 + key_index = jstad->curr_key_index;
2899 + if (!enc->length && (enc_ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
2900 + jstad->curr_key_index = key_index;
2901 + } else if ((enc_ext->alg == IW_ENCODE_ALG_NONE) || (flags & IW_ENCODE_DISABLED)) {
2902 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_OPEN;
2903 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_NONE;
2904 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2905 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
2906 + } else if (enc_ext->alg == IW_ENCODE_ALG_WEP) {
2907 + if (flags & IW_ENCODE_OPEN)
2908 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_OPEN;
2909 + else if (flags & IW_ENCODE_RESTRICTED)
2910 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_SHARED_KEY;
2912 + if (enc_ext->key_len > IW_ENCODING_TOKEN_MAX) {
2913 + err = -EINVAL;
2914 + goto done;
2917 + memcpy(jstad->key[key_index], enc_ext->key, enc_ext->key_len);
2918 + jstad->key_length[key_index] = enc_ext->key_len;
2919 + set_bit(key_index, &jstad->key_config_status);
2920 + } else if (enc_ext->alg == IW_ENCODE_ALG_PMK) {
2921 + if (enc_ext->key_len != PS3_JUPITER_STA_WPA_PSK_LENGTH) {
2922 + err = -EINVAL;
2923 + goto done;
2926 + memcpy(jstad->psk, enc_ext->key, enc_ext->key_len);
2927 + set_bit(PS3_JUPITER_STA_CONFIG_WPA_PSK_SET, &jstad->config_status);
2930 +done:
2932 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2934 + return err;
2938 + * ps3_jupiter_sta_get_encodeext
2939 + */
2940 +static int ps3_jupiter_sta_get_encodeext(struct net_device *netdev,
2941 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
2943 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
2944 + struct iw_point *enc = &wrqu->encoding;
2945 + struct iw_encode_ext *enc_ext = (struct iw_encode_ext *) extra;
2946 + int key_index = enc->flags & IW_ENCODE_INDEX;
2947 + unsigned long irq_flags;
2948 + int err = 0;
2950 + if ((enc->length - sizeof(struct iw_encode_ext)) < 0)
2951 + return -EINVAL;
2953 + if (key_index > PS3_JUPITER_STA_WEP_KEYS)
2954 + return -EINVAL;
2956 + spin_lock_irqsave(&jstad->lock, irq_flags);
2958 + if (key_index)
2959 + key_index--;
2960 + else
2961 + key_index = jstad->curr_key_index;
2963 + memset(enc_ext, 0, sizeof(*enc_ext));
2965 + switch (jstad->group_cipher_mode) {
2966 + case PS3_JUPITER_STA_CIPHER_WEP:
2967 + enc_ext->alg = IW_ENCODE_ALG_WEP;
2968 + enc->flags |= IW_ENCODE_ENABLED;
2969 + break;
2970 + case PS3_JUPITER_STA_CIPHER_TKIP:
2971 + enc_ext->alg = IW_ENCODE_ALG_TKIP;
2972 + enc->flags |= IW_ENCODE_ENABLED;
2973 + break;
2974 + case PS3_JUPITER_STA_CIPHER_AES:
2975 + enc_ext->alg = IW_ENCODE_ALG_CCMP;
2976 + enc->flags |= IW_ENCODE_ENABLED;
2977 + break;
2978 + default:
2979 + enc_ext->alg = IW_ENCODE_ALG_NONE;
2980 + enc->flags |= IW_ENCODE_NOKEY;
2983 + if (!(enc->flags & IW_ENCODE_NOKEY)) {
2984 + if ((enc->length - sizeof(struct iw_encode_ext)) < jstad->key_length[key_index]) {
2985 + err = -E2BIG;
2986 + goto done;
2989 + if (test_bit(key_index, &jstad->key_config_status))
2990 + memcpy(enc_ext->key, jstad->key[key_index], jstad->key_length[key_index]);
2993 +done:
2995 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
2997 + return err;
3001 + * ps3_jupiter_sta_set_genie
3002 + */
3003 +static int ps3_jupiter_sta_set_genie(struct net_device *netdev,
3004 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
3006 + /* XXX: implement */
3008 + return 0;
3012 + * ps3_jupiter_sta_get_genie
3013 + */
3014 +static int ps3_jupiter_sta_get_genie(struct net_device *netdev,
3015 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
3017 + /* XXX: implement */
3019 + return 0;
3023 + * ps3_jupiter_sta_set_mlme
3024 + */
3025 +static int ps3_jupiter_sta_set_mlme(struct net_device *netdev,
3026 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
3028 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3029 + struct iw_mlme *mlme = (struct iw_mlme *) extra;
3031 + switch (mlme->cmd) {
3032 + case IW_MLME_DEAUTH:
3033 + break;
3034 + case IW_MLME_DISASSOC:
3035 + ps3_jupiter_sta_disassoc(jstad);
3036 + break;
3037 + default:
3038 + return -EOPNOTSUPP;
3041 + return 0;
3044 +#ifdef CONFIG_WEXT_PRIV
3046 + * ps3_jupiter_sta_set_opmode
3047 + */
3048 +static int ps3_jupiter_sta_set_opmode(struct net_device *netdev,
3049 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
3051 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3052 + int opmode = *(int *) extra;
3053 + unsigned long irq_flags;
3054 + int err = 0;
3056 + spin_lock_irqsave(&jstad->lock, irq_flags);
3058 + switch (opmode) {
3059 + case PS3_JUPITER_STA_OPMODE_11B:
3060 + case PS3_JUPITER_STA_OPMODE_11G:
3061 + case PS3_JUPITER_STA_OPMODE_11BG:
3062 + jstad->opmode = opmode;
3063 + break;
3064 + default:
3065 + err = -EINVAL;
3068 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3070 + return err;
3074 + * ps3_jupiter_sta_get_opmode
3075 + */
3076 +static int ps3_jupiter_sta_get_opmode(struct net_device *netdev,
3077 + struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
3079 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3080 + unsigned long irq_flags;
3082 + spin_lock_irqsave(&jstad->lock, irq_flags);
3084 + memcpy(extra, &jstad->opmode, sizeof(jstad->opmode));
3085 + wrqu->data.length = sizeof(jstad->opmode);
3087 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3089 + return 0;
3091 +#endif
3094 + * ps3_jupiter_sta_get_wireless_stats
3095 + */
3096 +static struct iw_statistics *ps3_jupiter_sta_get_wireless_stats(struct net_device *netdev)
3098 + /* XXX: implement */
3100 + return NULL;
3104 + * ps3_jupiter_sta_open
3105 + */
3106 +static int ps3_jupiter_sta_open(struct net_device *netdev)
3108 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3110 + pr_debug("%s: called\n", __func__);
3112 + usb_unpoison_anchored_urbs(&jstad->tx_urb_anchor);
3114 + ps3_jupiter_sta_start_assoc(jstad);
3116 + netif_start_queue(netdev);
3118 + pr_debug("%s: done\n", __func__);
3120 + return 0;
3124 + * ps3_jupiter_sta_stop
3125 + */
3126 +static int ps3_jupiter_sta_stop(struct net_device *netdev)
3128 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3130 + pr_debug("%s: called\n", __func__);
3132 + netif_stop_queue(netdev);
3134 + cancel_delayed_work(&jstad->assoc_work);
3136 + if (jstad->assoc_status == PS3_JUPITER_STA_ASSOC_OK)
3137 + ps3_jupiter_sta_disassoc(jstad);
3139 + tasklet_kill(&jstad->rx_tasklet);
3140 + ps3_jupiter_sta_purge_rx_skb_queue(jstad);
3142 + ps3_jupiter_sta_free_tx_urbs(jstad);
3144 + ps3_jupiter_sta_free_scan_results(jstad);
3146 + ps3_jupiter_sta_reset_state(jstad);
3148 + pr_debug("%s: done\n", __func__);
3150 + return 0;
3154 + * ps3_jupiter_sta_start_xmit
3155 + */
3156 +static int ps3_jupiter_sta_start_xmit(struct sk_buff *skb, struct net_device *netdev)
3158 + struct ps3_jupiter_sta_dev *jstad = netdev_priv(netdev);
3160 + return ps3_jupiter_sta_tx_skb(jstad, skb);
3164 + * ps3_jupiter_sta_set_rx_mode
3165 + */
3166 +static void ps3_jupiter_sta_set_rx_mode(struct net_device *netdev)
3168 + /* XXX: implement */
3172 + * ps3_jupiter_sta_change_mtu
3173 + */
3174 +static int ps3_jupiter_sta_change_mtu(struct net_device *netdev, int new_mtu)
3176 + /* XXX: implement */
3178 + return 0;
3182 + * ps3_jupiter_sta_tx_timeout
3183 + */
3184 +static void ps3_jupiter_sta_tx_timeout(struct net_device *netdev)
3186 + /* XXX: implement */
3190 + * ps3_jupiter_sta_get_drvinfo
3191 + */
3192 +static void ps3_jupiter_sta_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
3194 + /* XXX: implement */
3198 + * ps3_jupiter_sta_get_link
3199 + */
3200 +static u32 ps3_jupiter_sta_get_link(struct net_device *netdev)
3202 + /* XXX: implement */
3204 + return 0;
3207 +static const iw_handler ps3_jupiter_sta_iw_handler[] =
3209 + IW_HANDLER(SIOCGIWNAME, ps3_jupiter_sta_get_name),
3210 + IW_HANDLER(SIOCGIWNICKN, ps3_jupiter_sta_get_nick),
3211 + IW_HANDLER(SIOCGIWRANGE, ps3_jupiter_sta_get_range),
3212 + IW_HANDLER(SIOCSIWMODE, ps3_jupiter_sta_set_mode),
3213 + IW_HANDLER(SIOCGIWMODE, ps3_jupiter_sta_get_mode),
3214 + IW_HANDLER(SIOCSIWFREQ, ps3_jupiter_sta_set_freq),
3215 + IW_HANDLER(SIOCGIWFREQ, ps3_jupiter_sta_get_freq),
3216 + IW_HANDLER(SIOCSIWSCAN, ps3_jupiter_sta_set_scan),
3217 + IW_HANDLER(SIOCGIWSCAN, ps3_jupiter_sta_get_scan),
3218 + IW_HANDLER(SIOCSIWAUTH, ps3_jupiter_sta_set_auth),
3219 + IW_HANDLER(SIOCGIWAUTH, ps3_jupiter_sta_get_auth),
3220 + IW_HANDLER(SIOCSIWESSID, ps3_jupiter_sta_set_essid),
3221 + IW_HANDLER(SIOCGIWESSID, ps3_jupiter_sta_get_essid),
3222 + IW_HANDLER(SIOCSIWAP, ps3_jupiter_sta_set_ap),
3223 + IW_HANDLER(SIOCGIWAP, ps3_jupiter_sta_get_ap),
3224 + IW_HANDLER(SIOCSIWENCODE, ps3_jupiter_sta_set_encode),
3225 + IW_HANDLER(SIOCGIWENCODE, ps3_jupiter_sta_get_encode),
3226 + IW_HANDLER(SIOCSIWENCODEEXT, ps3_jupiter_sta_set_encodeext),
3227 + IW_HANDLER(SIOCGIWENCODEEXT, ps3_jupiter_sta_get_encodeext),
3228 + IW_HANDLER(SIOCSIWGENIE, ps3_jupiter_sta_set_genie),
3229 + IW_HANDLER(SIOCGIWGENIE, ps3_jupiter_sta_get_genie),
3230 + IW_HANDLER(SIOCSIWMLME, ps3_jupiter_sta_set_mlme),
3233 +#ifdef CONFIG_WEXT_PRIV
3234 +static const iw_handler ps3_jupiter_sta_iw_priv_handler[] = {
3235 + ps3_jupiter_sta_set_opmode,
3236 + ps3_jupiter_sta_get_opmode,
3239 +enum {
3240 + PS3_JUPITER_STA_IW_PRIV_SET_OPMODE = SIOCIWFIRSTPRIV,
3241 + PS3_JUPITER_STA_IW_PRIV_GET_OPMODE,
3244 +static struct iw_priv_args ps3_jupiter_sta_iw_priv_args[] = {
3246 + .cmd = PS3_JUPITER_STA_IW_PRIV_SET_OPMODE,
3247 + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
3248 + .name = "set_opmode"
3249 + },
3251 + .cmd = PS3_JUPITER_STA_IW_PRIV_GET_OPMODE,
3252 + .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
3253 + .name = "get_opmode"
3254 + },
3256 +#endif
3258 +static const struct iw_handler_def ps3_jupiter_sta_iw_handler_def = {
3259 + .standard = ps3_jupiter_sta_iw_handler,
3260 + .num_standard = ARRAY_SIZE(ps3_jupiter_sta_iw_handler),
3261 +#ifdef CONFIG_WEXT_PRIV
3262 + .private = ps3_jupiter_sta_iw_priv_handler,
3263 + .num_private = ARRAY_SIZE(ps3_jupiter_sta_iw_priv_handler),
3264 + .private_args = ps3_jupiter_sta_iw_priv_args,
3265 + .num_private_args = ARRAY_SIZE(ps3_jupiter_sta_iw_priv_args),
3266 +#endif
3267 + .get_wireless_stats = ps3_jupiter_sta_get_wireless_stats,
3270 +static const struct net_device_ops ps3_jupiter_sta_net_device_ops = {
3271 + .ndo_open = ps3_jupiter_sta_open,
3272 + .ndo_stop = ps3_jupiter_sta_stop,
3273 + .ndo_start_xmit = ps3_jupiter_sta_start_xmit,
3274 + .ndo_set_rx_mode = ps3_jupiter_sta_set_rx_mode,
3275 + .ndo_change_mtu = ps3_jupiter_sta_change_mtu,
3276 + .ndo_tx_timeout = ps3_jupiter_sta_tx_timeout,
3277 + .ndo_set_mac_address = eth_mac_addr,
3278 + .ndo_validate_addr = eth_validate_addr,
3281 +static const struct ethtool_ops ps3_jupiter_sta_ethtool_ops = {
3282 + .get_drvinfo = ps3_jupiter_sta_get_drvinfo,
3283 + .get_link = ps3_jupiter_sta_get_link,
3287 + * ps3_jupiter_sta_rx_urb_complete
3288 + */
3289 +static void ps3_jupiter_sta_rx_urb_complete(struct urb *urb)
3291 + struct ps3_jupiter_sta_dev *jstad = usb_get_intfdata(usb_ifnum_to_if(urb->dev, PS3_JUPITER_STA_IFACE));
3292 + struct usb_device *udev = jstad->udev;
3293 + struct net_device *netdev = jstad->netdev;
3294 + struct sk_buff *skb = urb->context;
3295 + int err;
3297 + dev_dbg(&udev->dev, "Rx URB completed (%d)\n", urb->status);
3299 + switch (urb->status) {
3300 + case 0:
3301 + /* success */
3303 + if (urb->actual_length == 0x10) {
3304 + dev_info(&udev->dev, "got empty Rx URB\n");
3305 + break;
3308 + skb_put(skb, urb->actual_length);
3310 + err = ps3_jupiter_sta_prepare_rx_urb(jstad, urb);
3311 + if (err) {
3312 + dev_err(&udev->dev, "could not prepare Rx URB (%d)\n", err);
3313 + break;
3316 + skb_queue_tail(&jstad->rx_skb_queue, skb);
3318 + tasklet_schedule(&jstad->rx_tasklet);
3319 + break;
3320 + case -ECONNRESET:
3321 + case -ENOENT:
3322 + case -ESHUTDOWN:
3323 + case -ENODEV:
3324 + goto free_skb;
3325 + break;
3326 + default:
3327 + netdev->stats.rx_errors++;
3328 + dev_err(&udev->dev, "Rx URB failed (%d)\n", urb->status);
3331 + /* resubmit */
3333 + skb = urb->context;
3334 + skb_reset_tail_pointer(skb);
3335 + skb_trim(skb, 0);
3337 + usb_anchor_urb(urb, &jstad->rx_urb_anchor);
3339 + err = usb_submit_urb(urb, GFP_ATOMIC);
3340 + if (err) {
3341 + netdev->stats.rx_errors++;
3342 + usb_unanchor_urb(urb);
3343 + dev_err(&udev->dev, "could not submit Rx URB (%d)\n", err);
3344 + goto free_skb;
3347 + return;
3349 +free_skb:
3351 + dev_kfree_skb_irq(skb);
3355 + * ps3_jupiter_sta_tx_urb_complete
3356 + */
3357 +static void ps3_jupiter_sta_tx_urb_complete(struct urb *urb)
3359 + struct ps3_jupiter_sta_dev *jstad = usb_get_intfdata(usb_ifnum_to_if(urb->dev, PS3_JUPITER_STA_IFACE));
3360 + struct usb_device *udev = jstad->udev;
3361 + struct net_device *netdev = jstad->netdev;
3362 + struct sk_buff *skb = urb->context;
3363 + unsigned long irq_flags;
3365 + dev_dbg(&udev->dev, "Tx URB completed (%d)\n", urb->status);
3367 + switch (urb->status) {
3368 + case 0:
3369 + /* success */
3371 + spin_lock_irqsave(&jstad->lock, irq_flags);
3373 + netdev->stats.tx_packets++;
3374 + netdev->stats.tx_bytes += skb->len;
3376 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3378 + atomic_dec(&jstad->tx_submitted_urbs);
3379 + break;
3380 + case -ECONNRESET:
3381 + case -ENOENT:
3382 + case -ESHUTDOWN:
3383 + case -ENODEV:
3384 + break;
3385 + default:
3386 + netdev->stats.tx_errors++;
3387 + dev_err(&udev->dev, "Tx URB failed (%d)\n", urb->status);
3390 + dev_kfree_skb_irq(skb);
3394 + * ps3_jupiter_sta_tx_skb
3395 + */
3396 +static int ps3_jupiter_sta_tx_skb(struct ps3_jupiter_sta_dev *jstad, struct sk_buff *skb)
3398 + struct usb_device *udev = jstad->udev;
3399 + struct net_device *netdev = jstad->netdev;
3400 + struct urb *urb;
3401 + unsigned long irq_flags;
3402 + int err;
3404 + pr_debug("%s: called\n", __func__);
3406 + if (jstad->assoc_status != PS3_JUPITER_STA_ASSOC_OK) {
3407 + err = 0;
3408 + goto drop;
3411 + spin_lock_irqsave(&jstad->lock, irq_flags);
3413 + if (atomic_read(&jstad->tx_submitted_urbs) >= max_txurbs) {
3414 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3415 + dev_err(&udev->dev, "no free Tx URBs\n");
3416 + err = -EBUSY;
3417 + goto drop;
3420 + atomic_inc(&jstad->tx_submitted_urbs);
3422 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3424 + urb = usb_alloc_urb(0, GFP_ATOMIC);
3425 + if (!urb) {
3426 + atomic_dec(&jstad->tx_submitted_urbs);
3427 + dev_err(&udev->dev, "could not allocate Tx URB\n");
3428 + err = -ENOMEM;
3429 + goto drop;
3432 + usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, PS3_JUPITER_STA_EP),
3433 + skb->data, skb->len, ps3_jupiter_sta_tx_urb_complete, skb);
3434 + urb->transfer_flags |= URB_ZERO_PACKET;
3436 + usb_anchor_urb(urb, &jstad->tx_urb_anchor);
3437 + usb_free_urb(urb);
3439 + err = usb_submit_urb(urb, GFP_ATOMIC);
3440 + if (err) {
3441 + atomic_dec(&jstad->tx_submitted_urbs);
3442 + usb_unanchor_urb(urb);
3443 + dev_err(&udev->dev, "could not submit Tx URB (%d)\n", err);
3444 + goto drop;
3447 + pr_debug("%s: done\n", __func__);
3449 + return 0;
3451 +drop:
3453 + spin_lock_irqsave(&jstad->lock, irq_flags);
3454 + netdev->stats.tx_dropped++;
3455 + spin_unlock_irqrestore(&jstad->lock, irq_flags);
3456 + dev_kfree_skb_any(skb);
3458 + return err;
3462 + * ps3_jupiter_sta_free_scan_results
3463 + */
3464 +static void ps3_jupiter_sta_free_scan_results(struct ps3_jupiter_sta_dev *jstad)
3466 + struct ps3_jupiter_sta_scan_result *scan_result, *tmp;
3468 + list_for_each_entry_safe(scan_result, tmp, &jstad->scan_result_list, list) {
3469 + list_del(&scan_result->list);
3470 + kfree(scan_result);
3475 + * ps3_jupiter_sta_start_scan
3476 + */
3477 +static int ps3_jupiter_sta_start_scan(struct ps3_jupiter_sta_dev *jstad,
3478 + u8 *essid, size_t essid_length, u16 channels, u8 active, u16 channel_dwell)
3480 + struct ps3_eurus_cmd_start_scan *eurus_cmd_start_scan;
3481 + struct usb_device *udev = jstad->udev;
3482 + unsigned char *buf = NULL;
3483 + unsigned int payload_length, status;
3484 + unsigned int i, chan;
3485 + u8 *chan_ie, *essid_ie;
3486 + int err;
3488 + pr_debug("%s: called\n", __func__);
3490 +#ifdef DEBUG
3491 + if (essid && essid_length)
3492 + pr_debug("%s: essid %s\n", __func__, essid);
3493 +#endif
3495 + if (mutex_lock_interruptible(&jstad->scan_lock))
3496 + return -ERESTARTSYS;
3498 + if (jstad->scan_status == PS3_JUPITER_STA_SCAN_IN_PROGRESS) {
3499 + err = 0;
3500 + goto done;
3503 + dev_dbg(&udev->dev, "starting new scan\n");
3505 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
3506 + if (!buf) {
3507 + err = -ENOMEM;
3508 + goto done;
3511 + eurus_cmd_start_scan = (struct ps3_eurus_cmd_start_scan *) buf;
3512 + memset(eurus_cmd_start_scan, 0, 0x100);
3513 + eurus_cmd_start_scan->unknown2 = active;
3514 + eurus_cmd_start_scan->channel_dwell = cpu_to_le16(channel_dwell);
3516 + chan_ie = eurus_cmd_start_scan->ie;
3517 + chan_ie[0] = WLAN_EID_DS_PARAMS; /* ie id */
3518 + chan_ie[1] = 0x0; /* ie length */
3520 + for (i = 0, chan = 0; i < ARRAY_SIZE(ps3_jupiter_sta_channel_freq); i++) {
3521 + if (channels & (1 << i)) {
3522 + chan_ie[2 + chan] = i + 1;
3523 + chan++;
3527 + chan_ie[1] = chan; /* ie length */
3528 + payload_length = chan_ie + 2 + chan_ie[1] - (u8 *) eurus_cmd_start_scan;
3530 + if (essid && essid_length) {
3531 + essid_ie = chan_ie + 2 + chan_ie[1];
3532 + essid_ie[0] = WLAN_EID_SSID; /* ie id */
3533 + essid_ie[1] = essid_length; /* ie length */
3534 + memcpy(essid_ie + 2, essid, essid_length);
3536 + payload_length += 2 + essid_ie[1];
3539 + init_completion(&jstad->scan_done_comp);
3541 + jstad->scan_status = PS3_JUPITER_STA_SCAN_IN_PROGRESS;
3543 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_START_SCAN,
3544 + eurus_cmd_start_scan, payload_length, &status, NULL, NULL);
3545 + if (err)
3546 + goto done;
3548 + if (status != PS3_EURUS_CMD_OK) {
3549 + err = -EIO;
3550 + goto done;
3553 + err = 0;
3555 + pr_debug("%s: done\n", __func__);
3557 +done:
3559 + if (err)
3560 + jstad->scan_status = PS3_JUPITER_STA_SCAN_INVALID;
3562 + if (buf)
3563 + kfree(buf);
3565 + mutex_unlock(&jstad->scan_lock);
3567 + return err;
3571 + * ps3_jupiter_sta_get_scan_results
3572 + */
3573 +static int ps3_jupiter_sta_get_scan_results(struct ps3_jupiter_sta_dev *jstad)
3575 + struct ps3_eurus_cmd_get_scan_results *eurus_cmd_get_scan_results;
3576 + struct ps3_eurus_scan_result *eurus_scan_result;
3577 + struct ps3_jupiter_sta_scan_result *scan_result;
3578 + unsigned char *buf;
3579 + unsigned int status, response_length;
3580 + size_t eurus_scan_result_length, ie_length;
3581 + unsigned int i;
3582 + u8 *ie;
3583 + int err;
3585 + pr_debug("%s: called\n", __func__);
3587 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
3588 + if (!buf)
3589 + return -ENOMEM;
3591 + eurus_cmd_get_scan_results = (struct ps3_eurus_cmd_get_scan_results *) buf;
3592 + memset(eurus_cmd_get_scan_results, 0, PS3_EURUS_SCAN_RESULTS_MAXSIZE);
3594 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_GET_SCAN_RESULTS,
3595 + eurus_cmd_get_scan_results, PS3_EURUS_SCAN_RESULTS_MAXSIZE, &status,
3596 + &response_length, eurus_cmd_get_scan_results);
3597 + if (err)
3598 + goto done;
3600 + if (status != PS3_EURUS_CMD_OK) {
3601 + err = -EIO;
3602 + goto done;
3605 + /* free old scan results */
3607 + ps3_jupiter_sta_free_scan_results(jstad);
3609 + pr_debug("%s: number of scan results %d\n", __func__, eurus_cmd_get_scan_results->count);
3611 + /* add each scan result to list */
3613 + for (i = 0, eurus_scan_result = eurus_cmd_get_scan_results->result;
3614 + i < eurus_cmd_get_scan_results->count; i++) {
3615 + eurus_scan_result_length = le16_to_cpu(eurus_scan_result->length) +
3616 + sizeof(eurus_scan_result->length);
3617 + ie_length = (u8 *) eurus_scan_result + eurus_scan_result_length - eurus_scan_result->ie;
3619 + scan_result = kzalloc(sizeof(*scan_result) + ie_length, GFP_KERNEL);
3620 + if (!scan_result)
3621 + goto next;
3623 + memcpy(scan_result->bssid, eurus_scan_result->bssid, sizeof(eurus_scan_result->bssid));
3624 + scan_result->capability = le16_to_cpu(eurus_scan_result->capability);
3625 + scan_result->rssi = eurus_scan_result->rssi;
3627 + memcpy(scan_result->ie, eurus_scan_result->ie, ie_length);
3628 + scan_result->ie_length = ie_length;
3630 + for (ie = scan_result->ie;
3631 + ie < (scan_result->ie + scan_result->ie_length);
3632 + ie += (2 + ie[1])) {
3633 + switch (ie[0]) {
3634 + case WLAN_EID_SSID:
3635 + scan_result->essid_ie = ie;
3636 + break;
3637 + case WLAN_EID_SUPP_RATES:
3638 + scan_result->supp_rates_ie = ie;
3639 + break;
3640 + case WLAN_EID_DS_PARAMS:
3641 + scan_result->ds_param_set_ie = ie;
3642 + break;
3643 + case WLAN_EID_RSN:
3644 + scan_result->rsn_ie = ie;
3645 + break;
3646 + case WLAN_EID_EXT_SUPP_RATES:
3647 + scan_result->ext_supp_rates_ie = ie;
3648 + break;
3649 + case WLAN_EID_VENDOR_SPECIFIC:
3651 + /* WPA */
3653 + static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2 };
3655 + if (((sizeof(wpa_oui) + 1) <= ie[1]) &&
3656 + !memcmp(&ie[2], wpa_oui, sizeof(wpa_oui)) &&
3657 + (ie[2 + sizeof(wpa_oui)] == 0x1))
3658 + scan_result->wpa_ie = ie;
3660 + break;
3664 + list_add_tail(&scan_result->list, &jstad->scan_result_list);
3666 + next:
3668 + /* move to next scan result */
3670 + eurus_scan_result = (struct ps3_eurus_scan_result *) ((u8 *) eurus_scan_result +
3671 + eurus_scan_result_length);
3674 + err = 0;
3676 + pr_debug("%s: done\n", __func__);
3678 +done:
3680 + kfree(buf);
3682 + return err;
3686 + * ps3_jupiter_sta_translate_scan_result
3687 + */
3688 +static char *ps3_jupiter_sta_translate_scan_result(struct ps3_jupiter_sta_dev *jstad,
3689 + struct ps3_jupiter_sta_scan_result *scan_result,
3690 + struct iw_request_info *info, char *stream, char *ends)
3692 + struct iw_event iwe;
3693 + char *tmp;
3694 + unsigned int i;
3696 + memset(&iwe, 0, sizeof(iwe));
3697 + iwe.cmd = SIOCGIWAP;
3698 + iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3699 + memcpy(iwe.u.ap_addr.sa_data, scan_result->bssid, ETH_ALEN);
3700 + stream = iwe_stream_add_event(info, stream, ends, &iwe, IW_EV_ADDR_LEN);
3702 + if (scan_result->essid_ie) {
3703 + memset(&iwe, 0, sizeof(iwe));
3704 + iwe.cmd = SIOCGIWESSID;
3705 + iwe.u.data.flags = 1;
3706 + iwe.u.data.length = scan_result->essid_ie[1];
3707 + stream = iwe_stream_add_point(info, stream, ends, &iwe, &scan_result->essid_ie[2]);
3710 + if (scan_result->ds_param_set_ie) {
3711 + memset(&iwe, 0, sizeof(iwe));
3712 + iwe.cmd = SIOCGIWFREQ;
3713 + iwe.u.freq.m = scan_result->ds_param_set_ie[2];
3714 + iwe.u.freq.e = 0;
3715 + iwe.u.freq.i = 0;
3716 + stream = iwe_stream_add_event(info, stream, ends, &iwe, IW_EV_FREQ_LEN);
3719 + tmp = stream + iwe_stream_lcp_len(info);
3721 + if (scan_result->supp_rates_ie) {
3722 + for (i = 0; i < scan_result->supp_rates_ie[1]; i++) {
3723 + memset(&iwe, 0, sizeof(iwe));
3724 + iwe.cmd = SIOCGIWRATE;
3725 + iwe.u.bitrate.fixed = 0;
3726 + iwe.u.bitrate.disabled = 0;
3727 + iwe.u.bitrate.value = (scan_result->supp_rates_ie[2 + i] & 0x7f) * 500000;
3728 + tmp = iwe_stream_add_value(info, stream, tmp, ends, &iwe, IW_EV_PARAM_LEN);
3732 + if (scan_result->ext_supp_rates_ie) {
3733 + for (i = 0; i < scan_result->ext_supp_rates_ie[1]; i++) {
3734 + memset(&iwe, 0, sizeof(iwe));
3735 + iwe.cmd = SIOCGIWRATE;
3736 + iwe.u.bitrate.fixed = 0;
3737 + iwe.u.bitrate.disabled = 0;
3738 + iwe.u.bitrate.value = (scan_result->ext_supp_rates_ie[2 + i] & 0x7f) * 500000;
3739 + tmp = iwe_stream_add_value(info, stream, tmp, ends, &iwe, IW_EV_PARAM_LEN);
3743 + stream = tmp;
3745 + iwe.cmd = SIOCGIWMODE;
3746 + if (scan_result->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
3747 + if (scan_result->capability & WLAN_CAPABILITY_ESS)
3748 + iwe.u.mode = IW_MODE_MASTER;
3749 + else
3750 + iwe.u.mode = IW_MODE_ADHOC;
3751 + stream = iwe_stream_add_event(info, stream, ends, &iwe, IW_EV_UINT_LEN);
3754 + memset(&iwe, 0, sizeof(iwe));
3755 + iwe.cmd = SIOCGIWENCODE;
3756 + if (scan_result->capability & WLAN_CAPABILITY_PRIVACY)
3757 + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
3758 + else
3759 + iwe.u.data.flags = IW_ENCODE_DISABLED;
3760 + iwe.u.data.length = 0;
3761 + stream = iwe_stream_add_point(info, stream, ends, &iwe, scan_result->bssid);
3763 + if (scan_result->rsn_ie) {
3764 + memset(&iwe, 0, sizeof(iwe));
3765 + iwe.cmd = IWEVGENIE;
3766 + iwe.u.data.length = 2 + scan_result->rsn_ie[1];
3767 + stream = iwe_stream_add_point(info, stream, ends, &iwe, scan_result->rsn_ie);
3770 + if (scan_result->wpa_ie) {
3771 + memset(&iwe, 0, sizeof(iwe));
3772 + iwe.cmd = IWEVGENIE;
3773 + iwe.u.data.length = 2 + scan_result->wpa_ie[1];
3774 + stream = iwe_stream_add_point(info, stream, ends, &iwe, scan_result->wpa_ie);
3777 + memset(&iwe, 0, sizeof(iwe));
3778 + iwe.cmd = IWEVQUAL;
3779 + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
3780 + iwe.u.qual.level = ps3_eurus_rssi2percentage(scan_result->rssi);
3781 + iwe.u.qual.qual = ps3_eurus_rssi2percentage(scan_result->rssi);
3782 + iwe.u.qual.noise = 0;
3783 + stream = iwe_stream_add_event(info, stream, ends, &iwe, IW_EV_QUAL_LEN);
3785 + return stream;
3789 + * ps3_jupiter_sta_find_best_scan_result
3790 + */
3791 +static struct ps3_jupiter_sta_scan_result *ps3_jupiter_sta_find_best_scan_result(struct ps3_jupiter_sta_dev *jstad)
3793 + struct ps3_jupiter_sta_scan_result *scan_result, *best_scan_result;
3794 + u8 *essid;
3795 + unsigned int essid_length;
3797 + best_scan_result = NULL;
3799 + /* traverse scan results */
3801 + list_for_each_entry(scan_result, &jstad->scan_result_list, list) {
3802 + if (scan_result->essid_ie) {
3803 + essid = &scan_result->essid_ie[2];
3804 + essid_length = scan_result->essid_ie[1];
3805 + } else {
3806 + essid = NULL;
3807 + essid_length = 0;
3810 + if ((essid_length != jstad->essid_length) ||
3811 + strncmp(essid, jstad->essid, essid_length))
3812 + continue;
3814 + if (test_bit(PS3_JUPITER_STA_CONFIG_BSSID_SET, &jstad->config_status)) {
3815 + if (!ether_addr_equal(jstad->desired_bssid, scan_result->bssid)) {
3816 + best_scan_result = scan_result;
3817 + break;
3818 + } else {
3819 + continue;
3823 + switch (jstad->wpa_mode) {
3824 + case PS3_JUPITER_STA_WPA_MODE_NONE:
3825 + if ((jstad->group_cipher_mode == PS3_JUPITER_STA_CIPHER_WEP) &&
3826 + !(scan_result->capability & WLAN_CAPABILITY_PRIVACY))
3827 + continue;
3828 + break;
3829 + case PS3_JUPITER_STA_WPA_MODE_WPA:
3830 + if (!scan_result->wpa_ie)
3831 + continue;
3832 + break;
3833 + case PS3_JUPITER_STA_WPA_MODE_WPA2:
3834 + if (!scan_result->rsn_ie)
3835 + continue;
3836 + break;
3839 + if (!best_scan_result || (best_scan_result->rssi > scan_result->rssi))
3840 + best_scan_result = scan_result;
3843 + return best_scan_result;
3847 + * ps3_jupiter_sta_assoc
3848 + */
3849 +static int ps3_jupiter_sta_assoc(struct ps3_jupiter_sta_dev *jstad,
3850 + struct ps3_jupiter_sta_scan_result *scan_result)
3852 + struct ps3_eurus_cmd_0x1ed *eurus_cmd_0x1ed;
3853 + struct ps3_eurus_cmd_0x1025 *eurus_cmd_0x1025;
3854 + struct ps3_eurus_cmd_common_config *eurus_cmd_common_config;
3855 + struct ps3_eurus_cmd_wep_config *eurus_cmd_wep_config;
3856 + struct ps3_eurus_cmd_wpa_config *eurus_cmd_wpa_config;
3857 + struct ps3_eurus_cmd_associate *eurus_cmd_associate;
3858 + unsigned char *buf = NULL;
3859 + unsigned int payload_length, status;
3860 + u8 *ie;
3861 + int err;
3863 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
3864 + if (!buf)
3865 + return -ENOMEM;
3867 + eurus_cmd_0x1ed = (struct ps3_eurus_cmd_0x1ed *) buf;
3868 + memset(eurus_cmd_0x1ed, 0, sizeof(*eurus_cmd_0x1ed));
3869 + eurus_cmd_0x1ed->unknown2 = 0x1;
3870 + eurus_cmd_0x1ed->unknown3 = 0x2;
3871 + eurus_cmd_0x1ed->unknown4 = 0xff;
3872 + eurus_cmd_0x1ed->unknown5 = 0x16; /*XXX: 0x4 if AP doesn't support rate 54Mbps */
3873 + eurus_cmd_0x1ed->unknown6 = 0x4;
3874 + eurus_cmd_0x1ed->unknown7 = 0xa;
3875 + eurus_cmd_0x1ed->unknown8 = 0x16; /*XXX: 0x4 if AP doesn't support rate 54Mbps */
3877 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_0x1ed,
3878 + eurus_cmd_0x1ed, sizeof(*eurus_cmd_0x1ed), &status, NULL, NULL);
3879 + if (err)
3880 + goto done;
3882 + if (status != PS3_EURUS_CMD_OK) {
3883 + err = -EIO;
3884 + goto done;
3887 + /* set preamble mode */
3889 + eurus_cmd_0x1025 = (struct ps3_eurus_cmd_0x1025 *) buf;
3890 + memset(eurus_cmd_0x1025, 0, sizeof(*eurus_cmd_0x1025));
3892 + if (scan_result->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
3893 + eurus_cmd_0x1025->preamble_mode = PS3_EURUS_PREAMBLE_SHORT;
3894 + else
3895 + eurus_cmd_0x1025->preamble_mode = PS3_EURUS_PREAMBLE_LONG;
3897 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_0x1025,
3898 + eurus_cmd_0x1025, sizeof(*eurus_cmd_0x1025), &status, NULL, NULL);
3899 + if (err)
3900 + goto done;
3902 + if (status != PS3_EURUS_CMD_OK) {
3903 + err = -EIO;
3904 + goto done;
3907 + /* set common configuration */
3909 + eurus_cmd_common_config = (struct ps3_eurus_cmd_common_config *) buf;
3910 + memset(eurus_cmd_common_config, 0, sizeof(*eurus_cmd_common_config));
3912 + switch (jstad->bss_type) {
3913 + case PS3_JUPITER_STA_BSS_TYPE_INFRA:
3914 + eurus_cmd_common_config->bss_type = PS3_EURUS_BSS_INFRA;
3915 + break;
3916 + case PS3_JUPITER_STA_BSS_TYPE_ADHOC:
3917 + eurus_cmd_common_config->bss_type = PS3_EURUS_BSS_ADHOC;
3918 + break;
3921 + switch (jstad->auth_mode) {
3922 + case PS3_JUPITER_STA_AUTH_OPEN:
3923 + eurus_cmd_common_config->auth_mode = PS3_EURUS_AUTH_OPEN;
3924 + break;
3925 + case PS3_JUPITER_STA_AUTH_SHARED_KEY:
3926 + eurus_cmd_common_config->auth_mode = PS3_EURUS_AUTH_SHARED_KEY;
3927 + break;
3930 + switch (jstad->opmode) {
3931 + case PS3_JUPITER_STA_OPMODE_11B:
3932 + eurus_cmd_common_config->opmode = PS3_EURUS_OPMODE_11B;
3933 + break;
3934 + case PS3_JUPITER_STA_OPMODE_11G:
3935 + eurus_cmd_common_config->opmode = PS3_EURUS_OPMODE_11G;
3936 + break;
3937 + case PS3_JUPITER_STA_OPMODE_11BG:
3938 + eurus_cmd_common_config->opmode = PS3_EURUS_OPMODE_11BG;
3939 + break;
3942 + memcpy(eurus_cmd_common_config->bssid, scan_result->bssid, sizeof(scan_result->bssid));
3944 + eurus_cmd_common_config->capability = cpu_to_le16(scan_result->capability & ~WLAN_CAPABILITY_QOS);
3946 + payload_length = sizeof(*eurus_cmd_common_config);
3948 + ie = eurus_cmd_common_config->ie;
3950 + ie[0] = WLAN_EID_SSID;
3951 + ie[1] = jstad->essid_length;
3952 + memcpy(&ie[2], jstad->essid, jstad->essid_length);
3954 + payload_length += (2 + ie[1]);
3955 + ie += (2 + ie[1]);
3957 + if (scan_result->ds_param_set_ie) {
3958 + memcpy(ie, scan_result->ds_param_set_ie, 2 + scan_result->ds_param_set_ie[1]);
3960 + payload_length += (2 + ie[1]);
3961 + ie += (2 + ie[1]);
3964 + if (scan_result->supp_rates_ie) {
3965 + memcpy(ie, scan_result->supp_rates_ie, 2 + scan_result->supp_rates_ie[1]);
3967 + payload_length += (2 + scan_result->supp_rates_ie[1]);
3968 + ie += (2 + scan_result->supp_rates_ie[1]);
3971 + if (scan_result->ext_supp_rates_ie) {
3972 + memcpy(ie, scan_result->ext_supp_rates_ie, 2 + scan_result->ext_supp_rates_ie[1]);
3974 + payload_length += (2 + scan_result->ext_supp_rates_ie[1]);
3975 + ie += (2 + scan_result->ext_supp_rates_ie[1]);
3978 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_SET_COMMON_CONFIG,
3979 + eurus_cmd_common_config, payload_length, &status, NULL, NULL);
3980 + if (err)
3981 + goto done;
3983 + if (status != PS3_EURUS_CMD_OK) {
3984 + err = -EIO;
3985 + goto done;
3988 + if (jstad->wpa_mode == PS3_JUPITER_STA_WPA_MODE_NONE) {
3989 + /* set WEP configuration */
3991 + /* XXX: implement */
3993 + eurus_cmd_wep_config = (struct ps3_eurus_cmd_wep_config *) buf;
3994 + memset(eurus_cmd_wep_config, 0, sizeof(*eurus_cmd_wep_config));
3996 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_SET_WEP_CONFIG,
3997 + eurus_cmd_wep_config, sizeof(*eurus_cmd_wep_config), &status, NULL, NULL);
3998 + if (err)
3999 + goto done;
4001 + if (status != PS3_EURUS_CMD_OK) {
4002 + err = -EIO;
4003 + goto done;
4005 + } else {
4006 + /* set WPA configuration */
4008 + eurus_cmd_wpa_config = (struct ps3_eurus_cmd_wpa_config *) buf;
4009 + memset(eurus_cmd_wpa_config, 0, sizeof(*eurus_cmd_wpa_config));
4011 + eurus_cmd_wpa_config->unknown = 0x1;
4013 + switch (jstad->wpa_mode) {
4014 + case PS3_JUPITER_STA_WPA_MODE_WPA:
4015 + eurus_cmd_wpa_config->security_mode = PS3_EURUS_WPA_SECURITY_WPA;
4016 + if (jstad->group_cipher_mode == PS3_JUPITER_STA_CIPHER_TKIP)
4017 + eurus_cmd_wpa_config->group_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA_TKIP;
4018 + else
4019 + eurus_cmd_wpa_config->group_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA_AES;
4020 + if (jstad->pairwise_cipher_mode == PS3_JUPITER_STA_CIPHER_TKIP)
4021 + eurus_cmd_wpa_config->pairwise_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA_TKIP;
4022 + else
4023 + eurus_cmd_wpa_config->pairwise_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA_AES;
4024 + eurus_cmd_wpa_config->akm_suite = PS3_EURUS_WPA_AKM_SUITE_WPA_PSK;
4025 + break;
4026 + case PS3_JUPITER_STA_WPA_MODE_WPA2:
4027 + eurus_cmd_wpa_config->security_mode = PS3_EURUS_WPA_SECURITY_WPA2;
4028 + if (jstad->group_cipher_mode == PS3_JUPITER_STA_CIPHER_TKIP)
4029 + eurus_cmd_wpa_config->group_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA2_TKIP;
4030 + else
4031 + eurus_cmd_wpa_config->group_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA2_AES;
4032 + if (jstad->pairwise_cipher_mode == PS3_JUPITER_STA_CIPHER_TKIP)
4033 + eurus_cmd_wpa_config->pairwise_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA2_TKIP;
4034 + else
4035 + eurus_cmd_wpa_config->pairwise_cipher_suite = PS3_EURUS_WPA_CIPHER_SUITE_WPA2_AES;
4036 + eurus_cmd_wpa_config->akm_suite = PS3_EURUS_WPA_AKM_SUITE_WPA2_PSK;
4037 + break;
4038 + default:
4039 + /* should never happen */
4040 + BUG();
4043 + eurus_cmd_wpa_config->psk_type = PS3_EURUS_WPA_PSK_BIN;
4044 + memcpy(eurus_cmd_wpa_config->psk, jstad->psk, sizeof(jstad->psk));
4046 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_SET_WPA_CONFIG,
4047 + eurus_cmd_wpa_config, sizeof(*eurus_cmd_wpa_config), &status, NULL, NULL);
4048 + if (err)
4049 + goto done;
4051 + if (status != PS3_EURUS_CMD_OK) {
4052 + err = -EIO;
4053 + goto done;
4057 + init_completion(&jstad->assoc_done_comp);
4059 + jstad->assoc_status = PS3_JUPITER_STA_ASSOC_IN_PROGRESS;
4061 + eurus_cmd_associate = (struct ps3_eurus_cmd_associate *) buf;
4062 + memset(eurus_cmd_associate, 0, sizeof(*eurus_cmd_associate));
4064 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_ASSOCIATE,
4065 + eurus_cmd_associate, sizeof(*eurus_cmd_associate), &status, NULL, NULL);
4066 + if (err)
4067 + goto done;
4069 + if (status != PS3_EURUS_CMD_OK) {
4070 + err = -EIO;
4071 + goto done;
4074 + err = wait_for_completion_timeout(&jstad->assoc_done_comp, 5 * HZ);
4075 + if (!err) {
4076 + /* timeout */
4077 + ps3_jupiter_sta_disassoc(jstad);
4078 + err = -EIO;
4079 + goto done;
4082 + jstad->assoc_status = PS3_JUPITER_STA_ASSOC_OK;
4084 + memcpy(jstad->bssid, scan_result->bssid, sizeof(scan_result->bssid));
4086 + err = 0;
4088 +done:
4090 + if (err)
4091 + jstad->assoc_status = PS3_JUPITER_STA_ASSOC_INVALID;
4093 + kfree(buf);
4095 + return err;
4099 + * ps3_jupiter_sta_assoc_worker
4100 + */
4101 +static void ps3_jupiter_sta_assoc_worker(struct work_struct *work)
4103 + struct ps3_jupiter_sta_dev *jstad = container_of(work, struct ps3_jupiter_sta_dev, assoc_work.work);
4104 + struct usb_device *udev = jstad->udev;
4105 + u8 *essid;
4106 + unsigned int essid_length;
4107 + int scan_lock = 0;
4108 + struct ps3_jupiter_sta_scan_result *best_scan_result;
4109 + int err;
4111 + mutex_lock(&jstad->assoc_lock);
4113 + if (jstad->assoc_status != PS3_JUPITER_STA_ASSOC_INVALID) {
4114 + mutex_unlock(&jstad->assoc_lock);
4115 + return;
4118 + dev_dbg(&udev->dev, "starting new association\n");
4120 + if ((jstad->scan_status != PS3_JUPITER_STA_SCAN_OK) ||
4121 + time_after_eq(jiffies, jstad->scan_expires)) {
4122 + /* start scan and wait for scan results */
4124 + if (test_bit(PS3_JUPITER_STA_CONFIG_ESSID_SET, &jstad->config_status)) {
4125 + essid = jstad->essid;
4126 + essid_length = jstad->essid_length;
4127 + } else {
4128 + essid = NULL;
4129 + essid_length = 0;
4132 + err = ps3_jupiter_sta_start_scan(jstad, essid, essid_length, jstad->channel_info,
4133 + 1, PS3_JUPITER_STA_CHANNEL_DWELL);
4134 + if (err)
4135 + goto done;
4137 + wait_for_completion(&jstad->scan_done_comp);
4140 + mutex_lock(&jstad->scan_lock);
4141 + scan_lock = 1;
4143 + if (jstad->scan_status != PS3_JUPITER_STA_SCAN_OK)
4144 + goto done;
4146 + best_scan_result = ps3_jupiter_sta_find_best_scan_result(jstad);
4147 + if (!best_scan_result) {
4148 + dev_dbg(&udev->dev, "no suitable scan result was found\n");
4149 + goto done;
4152 + err = ps3_jupiter_sta_assoc(jstad, best_scan_result);
4153 + if (err) {
4154 + dev_dbg(&udev->dev, "association failed (%d)\n", err);
4155 + goto done;
4158 +done:
4160 + if (scan_lock)
4161 + mutex_unlock(&jstad->scan_lock);
4163 + if (jstad->assoc_status == PS3_JUPITER_STA_ASSOC_OK)
4164 + ps3_jupiter_sta_send_iw_ap_event(jstad, jstad->bssid);
4165 + else
4166 + ps3_jupiter_sta_send_iw_ap_event(jstad, NULL);
4168 + mutex_unlock(&jstad->assoc_lock);
4172 + * ps3_jupiter_sta_start_assoc
4173 + */
4174 +static void ps3_jupiter_sta_start_assoc(struct ps3_jupiter_sta_dev *jstad)
4176 + pr_debug("%s: called\n", __func__);
4178 + if (!test_bit(PS3_JUPITER_STA_READY, &jstad->status))
4179 + return;
4181 + if (!test_bit(PS3_JUPITER_STA_CONFIG_ESSID_SET, &jstad->config_status))
4182 + return;
4184 + if ((jstad->wpa_mode == PS3_JUPITER_STA_WPA_MODE_NONE) &&
4185 + (jstad->group_cipher_mode == PS3_JUPITER_STA_CIPHER_WEP) &&
4186 + !jstad->key_config_status)
4187 + return;
4189 + if ((jstad->wpa_mode != PS3_JUPITER_STA_WPA_MODE_NONE) &&
4190 + !test_bit(PS3_JUPITER_STA_CONFIG_WPA_PSK_SET, &jstad->config_status))
4191 + return;
4193 + queue_delayed_work(jstad->assoc_queue, &jstad->assoc_work, 0);
4195 + pr_debug("%s: done\n", __func__);
4199 + * ps3_jupiter_sta_disassoc
4200 + */
4201 +static int ps3_jupiter_sta_disassoc(struct ps3_jupiter_sta_dev *jstad)
4203 + struct ps3_eurus_cmd_disassociate *eurus_cmd_disassociate;
4204 + unsigned char *buf = NULL;
4205 + unsigned int status;
4206 + int err;
4208 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
4209 + if (!buf)
4210 + return -ENOMEM;
4212 + eurus_cmd_disassociate = (struct ps3_eurus_cmd_disassociate *) buf;
4213 + memset(eurus_cmd_disassociate, 0, sizeof(*eurus_cmd_disassociate));
4215 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_DISASSOCIATE,
4216 + eurus_cmd_disassociate, sizeof(*eurus_cmd_disassociate), &status, NULL, NULL);
4217 + if (err)
4218 + goto done;
4220 + if (status != PS3_EURUS_CMD_OK) {
4221 + err = -EIO;
4222 + goto done;
4225 + err = 0;
4227 +done:
4229 + kfree(buf);
4231 + return err;
4235 + * ps3_jupiter_sta_event_scan_completed
4236 + */
4237 +static void ps3_jupiter_sta_event_scan_completed(struct ps3_jupiter_sta_dev *jstad)
4239 + union iwreq_data iwrd;
4240 + int err;
4242 + mutex_lock(&jstad->scan_lock);
4244 + err = ps3_jupiter_sta_get_scan_results(jstad);
4245 + if (err)
4246 + goto done;
4248 + jstad->scan_expires = jiffies + PS3_JUPITER_STA_SCAN_VALID_TIME_SEC * HZ;
4249 + jstad->scan_status = PS3_JUPITER_STA_SCAN_OK;
4251 + complete(&jstad->scan_done_comp);
4253 + memset(&iwrd, 0, sizeof(iwrd));
4254 + wireless_send_event(jstad->netdev, SIOCGIWSCAN, &iwrd, NULL);
4256 +done:
4258 + if (err)
4259 + jstad->scan_status = PS3_JUPITER_STA_SCAN_INVALID;
4261 + mutex_unlock(&jstad->scan_lock);
4265 + * ps3_jupiter_sta_event_connected
4266 + */
4267 +static void ps3_jupiter_sta_event_connected(struct ps3_jupiter_sta_dev *jstad, u32 event_id)
4269 + u32 expected_event_id = 0;
4271 + switch (jstad->wpa_mode) {
4272 + case PS3_JUPITER_STA_WPA_MODE_NONE:
4273 + expected_event_id = PS3_EURUS_EVENT_CONNECTED;
4274 + break;
4275 + case PS3_JUPITER_STA_WPA_MODE_WPA:
4276 + case PS3_JUPITER_STA_WPA_MODE_WPA2:
4277 + expected_event_id = PS3_EURUS_EVENT_WPA_CONNECTED;
4278 + break;
4279 + default:
4280 + return;
4283 + if (expected_event_id == event_id) {
4284 + complete(&jstad->assoc_done_comp);
4285 + netif_carrier_on(jstad->netdev);
4290 + * ps3_jupiter_sta_event_disconnected
4291 + */
4292 +static void ps3_jupiter_sta_event_disconnected(struct ps3_jupiter_sta_dev *jstad)
4294 + int assoc_lock = 0;
4296 + if (mutex_trylock(&jstad->assoc_lock))
4297 + assoc_lock = 1;
4299 + ps3_jupiter_sta_disassoc(jstad);
4301 + if (jstad->assoc_status == PS3_JUPITER_STA_ASSOC_OK)
4302 + ps3_jupiter_sta_send_iw_ap_event(jstad, NULL);
4304 + jstad->assoc_status = PS3_JUPITER_STA_ASSOC_INVALID;
4306 + netif_carrier_off(jstad->netdev);
4308 + if (assoc_lock)
4309 + mutex_unlock(&jstad->assoc_lock);
4313 + * ps3_jupiter_sta_event_handler
4314 + */
4315 +static int ps3_jupiter_sta_event_handler(struct notifier_block *n,
4316 + unsigned long val, void *v)
4318 + struct ps3_jupiter_sta_dev *jstad = container_of(n, struct ps3_jupiter_sta_dev, event_listener);
4319 + struct usb_device *udev = jstad->udev;
4320 + struct ps3_eurus_event *event = v;
4322 + dev_dbg(&udev->dev, "got event (0x%08x 0x%08x 0x%08x 0x%08x 0x%08x)\n",
4323 + event->hdr.type, event->hdr.id, event->hdr.timestamp,
4324 + event->hdr.payload_length, event->hdr.unknown);
4326 + switch (event->hdr.type) {
4327 + case PS3_EURUS_EVENT_TYPE_0x40:
4328 + switch (event->hdr.id) {
4329 + case PS3_EURUS_EVENT_DEAUTH:
4330 + ps3_jupiter_sta_event_disconnected(jstad);
4331 + break;
4333 + break;
4334 + case PS3_EURUS_EVENT_TYPE_0x80:
4335 + switch (event->hdr.id) {
4336 + case PS3_EURUS_EVENT_SCAN_COMPLETED:
4337 + ps3_jupiter_sta_event_scan_completed(jstad);
4338 + break;
4339 + case PS3_EURUS_EVENT_CONNECTED:
4340 + case PS3_EURUS_EVENT_WPA_CONNECTED:
4341 + ps3_jupiter_sta_event_connected(jstad, event->hdr.id);
4342 + break;
4343 + case PS3_EURUS_EVENT_BEACON_LOST:
4344 + ps3_jupiter_sta_event_disconnected(jstad);
4345 + break;
4347 + break;
4350 + return NOTIFY_OK;
4354 + * ps3_jupiter_sta_set_mac_addr
4355 + */
4356 +static int ps3_jupiter_sta_set_mac_addr(struct ps3_jupiter_sta_dev *jstad)
4358 + struct usb_device *udev = jstad->udev;
4359 + struct net_device *netdev = jstad->netdev;
4360 + struct ps3_eurus_cmd_get_mac_addr_list *eurus_cmd_get_mac_addr_list;
4361 + struct ps3_eurus_cmd_set_mac_addr *eurus_cmd_set_mac_addr;
4362 + struct ps3_eurus_cmd_0x115b *eurus_cmd_0x115b;
4363 + unsigned char *buf = NULL;
4364 + unsigned int status, response_length;
4365 + int err;
4367 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
4368 + if (!buf)
4369 + return -ENOMEM;
4371 + /* get MAC address list */
4373 + eurus_cmd_get_mac_addr_list = (struct ps3_eurus_cmd_get_mac_addr_list *) buf;
4374 + memset(eurus_cmd_get_mac_addr_list, 0, PS3_EURUS_MAC_ADDR_LIST_MAXSIZE);
4376 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_GET_MAC_ADDR_LIST,
4377 + eurus_cmd_get_mac_addr_list, PS3_EURUS_MAC_ADDR_LIST_MAXSIZE, &status,
4378 + &response_length, eurus_cmd_get_mac_addr_list);
4379 + if (err)
4380 + goto done;
4382 + if (status != PS3_EURUS_CMD_OK) {
4383 + err = -EIO;
4384 + goto done;
4387 + /* use first MAC address */
4389 + memcpy(netdev->dev_addr, eurus_cmd_get_mac_addr_list->mac_addr, ETH_ALEN);
4391 + dev_info(&udev->dev, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
4392 + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
4393 + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
4395 + /* set MAC address */
4397 + eurus_cmd_set_mac_addr = (struct ps3_eurus_cmd_set_mac_addr *) buf;
4398 + memset(eurus_cmd_set_mac_addr, 0, sizeof(*eurus_cmd_set_mac_addr));
4399 + memcpy(eurus_cmd_set_mac_addr->mac_addr, netdev->dev_addr, ETH_ALEN);
4401 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_SET_MAC_ADDR,
4402 + eurus_cmd_set_mac_addr, sizeof(*eurus_cmd_set_mac_addr), &status, NULL, NULL);
4403 + if (err)
4404 + goto done;
4406 + if (status != PS3_EURUS_CMD_OK) {
4407 + err = -EIO;
4408 + goto done;
4411 + eurus_cmd_0x115b = (struct ps3_eurus_cmd_0x115b *) buf;
4412 + memset(eurus_cmd_0x115b, 0, sizeof(*eurus_cmd_0x115b));
4413 + eurus_cmd_0x115b->unknown1 = cpu_to_le16(0x1);
4414 + eurus_cmd_0x115b->unknown2 = cpu_to_le16(0x0);
4415 + memcpy(eurus_cmd_0x115b->mac_addr, netdev->dev_addr, ETH_ALEN);
4417 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_0x115b,
4418 + eurus_cmd_0x115b, sizeof(*eurus_cmd_0x115b), &status, NULL, NULL);
4419 + if (err)
4420 + goto done;
4422 + if (status != PS3_EURUS_CMD_OK) {
4423 + err = -EIO;
4424 + goto done;
4427 + err = 0;
4429 +done:
4431 + kfree(buf);
4433 + return err;
4437 + * ps3_jupiter_sta_get_channel_info
4438 + */
4439 +static int ps3_jupiter_sta_get_channel_info(struct ps3_jupiter_sta_dev *jstad)
4441 + struct ps3_eurus_cmd_get_channel_info *eurus_cmd_get_channel_info;
4442 + unsigned char *buf = NULL;
4443 + unsigned int status, response_length;
4444 + int err;
4446 + buf = kmalloc(PS3_JUPITER_STA_CMD_BUFSIZE, GFP_KERNEL);
4447 + if (!buf)
4448 + return -ENOMEM;
4450 + eurus_cmd_get_channel_info = (struct ps3_eurus_cmd_get_channel_info *) buf;
4451 + memset(eurus_cmd_get_channel_info, 0, sizeof(*eurus_cmd_get_channel_info));
4453 + err = ps3_jupiter_exec_eurus_cmd(PS3_EURUS_CMD_GET_CHANNEL_INFO,
4454 + eurus_cmd_get_channel_info, sizeof(*eurus_cmd_get_channel_info), &status,
4455 + &response_length, eurus_cmd_get_channel_info);
4456 + if (err)
4457 + goto done;
4459 + if (status != PS3_EURUS_CMD_OK) {
4460 + err = -EIO;
4461 + goto done;
4464 + jstad->channel_info = eurus_cmd_get_channel_info->channel_info;
4466 + err = 0;
4468 +done:
4470 + kfree(buf);
4472 + return err;
4476 + * ps3_jupiter_sta_reset_state
4477 + */
4478 +static void ps3_jupiter_sta_reset_state(struct ps3_jupiter_sta_dev *jstad)
4480 + jstad->scan_status = PS3_JUPITER_STA_SCAN_INVALID;
4482 + jstad->config_status = 0;
4484 + jstad->opmode = PS3_JUPITER_STA_OPMODE_11G;
4486 + jstad->auth_mode = PS3_JUPITER_STA_AUTH_OPEN;
4488 + jstad->wpa_mode = PS3_JUPITER_STA_WPA_MODE_NONE;
4489 + jstad->group_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
4490 + jstad->pairwise_cipher_mode = PS3_JUPITER_STA_CIPHER_NONE;
4492 + memset(jstad->essid, 0, sizeof(jstad->essid));
4493 + jstad->essid_length = 0;
4495 + memset(jstad->desired_bssid, 0, sizeof(jstad->desired_bssid));
4497 + jstad->channel = 0;
4499 + jstad->key_config_status = 0;
4500 + jstad->curr_key_index = 0;
4502 + jstad->assoc_status = PS3_JUPITER_STA_ASSOC_INVALID;
4506 + * ps3_jupiter_sta_create_assoc_worker
4507 + */
4508 +static int ps3_jupiter_sta_create_assoc_worker(struct ps3_jupiter_sta_dev *jstad)
4510 + jstad->assoc_queue = create_singlethread_workqueue("ps3_jupiter_sta_assoc");
4511 + if (!jstad->assoc_queue)
4512 + return -ENOMEM;
4514 + INIT_DELAYED_WORK(&jstad->assoc_work, ps3_jupiter_sta_assoc_worker);
4516 + return 0;
4520 + * ps3_jupiter_sta_destroy_assoc_worker
4521 + */
4522 +static void ps3_jupiter_sta_destroy_assoc_worker(struct ps3_jupiter_sta_dev *jstad)
4524 + if (jstad->assoc_queue) {
4525 + cancel_delayed_work(&jstad->assoc_work);
4526 + flush_workqueue(jstad->assoc_queue);
4527 + destroy_workqueue(jstad->assoc_queue);
4528 + jstad->assoc_queue = NULL;
4533 + * ps3_jupiter_sta_prepare_rx_urb
4534 + */
4535 +static int ps3_jupiter_sta_prepare_rx_urb(struct ps3_jupiter_sta_dev *jstad,
4536 + struct urb *urb)
4538 + struct usb_device *udev = jstad->udev;
4539 + struct sk_buff *skb;
4541 + skb = dev_alloc_skb(PS3_JUPITER_STA_RX_BUFSIZE);
4542 + if (!skb)
4543 + return -ENOMEM;
4545 + usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, PS3_JUPITER_STA_EP),
4546 + skb->data, PS3_JUPITER_STA_RX_BUFSIZE, ps3_jupiter_sta_rx_urb_complete, skb);
4548 + return 0;
4552 + * ps3_jupiter_sta_alloc_rx_urbs
4553 + */
4554 +static int ps3_jupiter_sta_alloc_rx_urbs(struct ps3_jupiter_sta_dev *jstad)
4556 + struct usb_device *udev = jstad->udev;
4557 + struct urb *urb;
4558 + unsigned int i;
4559 + int err;
4561 + pr_debug("%s: called\n", __func__);
4563 + init_usb_anchor(&jstad->rx_urb_anchor);
4565 + for (i = 0; i < PS3_JUPITER_STA_RX_URBS; i++) {
4566 + urb = usb_alloc_urb(0, GFP_KERNEL);
4567 + if (!urb) {
4568 + dev_err(&udev->dev, "could not allocate Rx URB\n");
4569 + err = -ENOMEM;
4570 + goto done;
4573 + err = ps3_jupiter_sta_prepare_rx_urb(jstad, urb);
4574 + if (err) {
4575 + dev_err(&udev->dev, "could not prepare Rx URB (%d)\n", err);
4576 + usb_free_urb(urb);
4577 + goto done;
4580 + usb_anchor_urb(urb, &jstad->rx_urb_anchor);
4581 + usb_free_urb(urb);
4583 + err = usb_submit_urb(urb, GFP_KERNEL);
4584 + if (err) {
4585 + dev_err(&udev->dev, "could not submit Rx URB (%d)\n", err);
4586 + dev_kfree_skb_any(urb->context);
4587 + usb_unanchor_urb(urb);
4588 + goto done;
4592 + err = 0;
4594 + pr_debug("%s: done\n", __func__);
4596 +done:
4598 + if (err)
4599 + usb_kill_anchored_urbs(&jstad->rx_urb_anchor);
4601 + return err;
4605 + * ps3_jupiter_sta_free_rx_urbs
4606 + */
4607 +static void ps3_jupiter_sta_free_rx_urbs(struct ps3_jupiter_sta_dev *jstad)
4609 + usb_kill_anchored_urbs(&jstad->rx_urb_anchor);
4611 + usb_poison_anchored_urbs(&jstad->rx_urb_anchor);
4615 + * ps3_jupiter_sta_rx_tasklet
4616 + */
4617 +static void ps3_jupiter_sta_rx_tasklet(unsigned long data)
4619 + struct ps3_jupiter_sta_dev *jstad = (struct ps3_jupiter_sta_dev *) data;
4620 + struct net_device *netdev = jstad->netdev;
4621 + struct sk_buff *skb;
4623 + while ((skb = skb_dequeue(&jstad->rx_skb_queue))) {
4624 + skb->protocol = eth_type_trans(skb, netdev);
4626 + netdev->stats.rx_packets++;
4627 + netdev->stats.rx_bytes += skb->len;
4629 + netif_receive_skb(skb);
4634 + * ps3_jupiter_sta_purge_rx_skb_queue
4635 + */
4636 +static void ps3_jupiter_sta_purge_rx_skb_queue(struct ps3_jupiter_sta_dev *jstad)
4638 + struct sk_buff *skb;
4639 + unsigned long irq_flags;
4641 + spin_lock_irqsave(&jstad->rx_skb_queue.lock, irq_flags);
4643 + while ((skb = __skb_dequeue(&jstad->rx_skb_queue)))
4644 + dev_kfree_skb_any(skb);
4646 + spin_unlock_irqrestore(&jstad->rx_skb_queue.lock, irq_flags);
4650 + * ps3_jupiter_sta_free_tx_urbs
4651 + */
4652 +static void ps3_jupiter_sta_free_tx_urbs(struct ps3_jupiter_sta_dev *jstad)
4654 + usb_wait_anchor_empty_timeout(&jstad->tx_urb_anchor, msecs_to_jiffies(100));
4656 + usb_kill_anchored_urbs(&jstad->tx_urb_anchor);
4658 + usb_poison_anchored_urbs(&jstad->tx_urb_anchor);
4662 + * ps3_jupiter_sta_probe
4663 + */
4664 +static int ps3_jupiter_sta_probe(struct usb_interface *interface,
4665 + const struct usb_device_id *id)
4667 + struct usb_device *udev = interface_to_usbdev(interface);
4668 + struct ps3_jupiter_sta_dev *jstad;
4669 + struct net_device *netdev;
4670 + int err;
4672 + netdev = alloc_etherdev(sizeof(struct ps3_jupiter_sta_dev));
4673 + if (!netdev)
4674 + return -ENOMEM;
4676 + SET_NETDEV_DEV(netdev, &udev->dev);
4678 + strcpy(netdev->name, "wlan%d");
4680 + netdev->ethtool_ops = &ps3_jupiter_sta_ethtool_ops;
4681 + netdev->netdev_ops = &ps3_jupiter_sta_net_device_ops;
4682 + netdev->wireless_data = &jstad->wireless_data;
4683 + netdev->wireless_handlers = &ps3_jupiter_sta_iw_handler_def;
4685 + jstad = netdev_priv(netdev);
4686 + jstad->netdev = netdev;
4688 + jstad->udev = usb_get_dev(udev);
4689 + usb_set_intfdata(interface, jstad);
4691 + err = ps3_jupiter_sta_set_mac_addr(jstad);
4692 + if (err) {
4693 + dev_err(&udev->dev, "could not setup network device (%d)\n", err);
4694 + goto fail_free_netdev;
4697 + spin_lock_init(&jstad->lock);
4699 + jstad->event_listener.notifier_call = ps3_jupiter_sta_event_handler;
4701 + err = ps3_jupiter_register_event_listener(&jstad->event_listener);
4702 + if (err) {
4703 + dev_err(&udev->dev, "could not register event listener (%d)\n", err);
4704 + goto fail_free_netdev;
4707 + mutex_init(&jstad->scan_lock);
4708 + INIT_LIST_HEAD(&jstad->scan_result_list);
4710 + err = ps3_jupiter_sta_get_channel_info(jstad);
4711 + if (err) {
4712 + dev_err(&udev->dev, "could not get channel info (%d)\n", err);
4713 + goto fail_unregister_event_listener;
4716 + mutex_init(&jstad->assoc_lock);
4718 + err = ps3_jupiter_sta_create_assoc_worker(jstad);
4719 + if (err) {
4720 + dev_err(&udev->dev, "could not create assoc work queue (%d)\n", err);
4721 + goto fail_unregister_event_listener;
4724 + skb_queue_head_init(&jstad->rx_skb_queue);
4725 + tasklet_init(&jstad->rx_tasklet, ps3_jupiter_sta_rx_tasklet, (unsigned long) jstad);
4727 + err = ps3_jupiter_sta_alloc_rx_urbs(jstad);
4728 + if (err) {
4729 + dev_err(&udev->dev, "could not allocate Rx URBs (%d)\n", err);
4730 + goto fail_destroy_assoc_worker;
4733 + init_usb_anchor(&jstad->tx_urb_anchor);
4734 + atomic_set(&jstad->tx_submitted_urbs, 0);
4736 + ps3_jupiter_sta_reset_state(jstad);
4738 + set_bit(PS3_JUPITER_STA_READY, &jstad->status);
4740 + err = register_netdev(netdev);
4741 + if (err) {
4742 + dev_dbg(&udev->dev, "could not register network device %s (%d)\n", netdev->name, err);
4743 + goto fail_free_rx_urbs;
4746 + return 0;
4748 +fail_free_rx_urbs:
4750 + ps3_jupiter_sta_free_rx_urbs(jstad);
4752 +fail_destroy_assoc_worker:
4754 + ps3_jupiter_sta_destroy_assoc_worker(jstad);
4756 +fail_unregister_event_listener:
4758 + ps3_jupiter_unregister_event_listener(&jstad->event_listener);
4760 +fail_free_netdev:
4762 + usb_set_intfdata(interface, NULL);
4763 + usb_put_dev(udev);
4765 + free_netdev(netdev);
4767 + return err;
4771 + * ps3_jupiter_sta_disconnect
4772 + */
4773 +static void ps3_jupiter_sta_disconnect(struct usb_interface *interface)
4775 + struct ps3_jupiter_sta_dev *jstad = usb_get_intfdata(interface);
4776 + struct usb_device *udev = jstad->udev;
4777 + struct net_device *netdev = jstad->netdev;
4779 + clear_bit(PS3_JUPITER_STA_READY, &jstad->status);
4781 + unregister_netdev(netdev);
4783 + if (jstad->assoc_status == PS3_JUPITER_STA_ASSOC_OK)
4784 + ps3_jupiter_sta_disassoc(jstad);
4786 + ps3_jupiter_sta_destroy_assoc_worker(jstad);
4788 + ps3_jupiter_sta_free_rx_urbs(jstad);
4789 + tasklet_kill(&jstad->rx_tasklet);
4790 + ps3_jupiter_sta_purge_rx_skb_queue(jstad);
4792 + ps3_jupiter_sta_free_tx_urbs(jstad);
4794 + ps3_jupiter_sta_free_scan_results(jstad);
4796 + ps3_jupiter_unregister_event_listener(&jstad->event_listener);
4798 + usb_set_intfdata(interface, NULL);
4799 + usb_put_dev(udev);
4801 + free_netdev(netdev);
4804 +#ifdef CONFIG_PM
4806 + * ps3_jupiter_sta_suspend
4807 + */
4808 +static int ps3_jupiter_sta_suspend(struct usb_interface *interface, pm_message_t state)
4810 + /* XXX: implement */
4812 + return 0;
4816 + * ps3_jupiter_sta_resume
4817 + */
4818 +static int ps3_jupiter_sta_resume(struct usb_interface *interface)
4820 + /* XXX: implement */
4822 + return 0;
4824 +#endif /* CONFIG_PM */
4826 +static struct usb_device_id ps3_jupiter_sta_devtab[] = {
4828 + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
4829 + .idVendor = 0x054c,
4830 + .idProduct = 0x036f,
4831 + .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
4832 + .bInterfaceSubClass = 2,
4833 + .bInterfaceProtocol = 2
4834 + },
4835 + { }
4838 +static struct usb_driver ps3_jupiter_sta_drv = {
4839 + .name = KBUILD_MODNAME,
4840 + .id_table = ps3_jupiter_sta_devtab,
4841 + .probe = ps3_jupiter_sta_probe,
4842 + .disconnect = ps3_jupiter_sta_disconnect,
4843 +#ifdef CONFIG_PM
4844 + .suspend = ps3_jupiter_sta_suspend,
4845 + .resume = ps3_jupiter_sta_resume,
4846 +#endif /* CONFIG_PM */
4850 + * ps3_jupiter_sta_init
4851 + */
4852 +static int __init ps3_jupiter_sta_init(void)
4854 + return usb_register(&ps3_jupiter_sta_drv);
4858 + * ps3_jupiter_sta_exit
4859 + */
4860 +static void __exit ps3_jupiter_sta_exit(void)
4862 + usb_deregister(&ps3_jupiter_sta_drv);
4865 +module_init(ps3_jupiter_sta_init);
4866 +module_exit(ps3_jupiter_sta_exit);
4868 +MODULE_SUPPORTED_DEVICE("PS3 Jupiter STA");
4869 +MODULE_DEVICE_TABLE(usb, ps3_jupiter_sta_devtab);
4870 +MODULE_DESCRIPTION("PS3 Jupiter STA");
4871 +MODULE_AUTHOR("glevand");
4872 +MODULE_LICENSE("GPL");