diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw')
-rw-r--r-- | drivers/net/wireless/zd1211rw/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.c | 145 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.h | 21 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 229 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.h | 25 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_rf_uw2453.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 27 |
7 files changed, 260 insertions, 190 deletions
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index 74b31eafe72d..5f809695f71a 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config ZD1211RW | 1 | config ZD1211RW |
2 | tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" | 2 | tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" |
3 | depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL | 3 | depends on USB && MAC80211 && EXPERIMENTAL |
4 | select FW_LOADER | 4 | select FW_LOADER |
5 | ---help--- | 5 | ---help--- |
6 | This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless | 6 | This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 4e79a9800134..b2af3c549bb3 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/slab.h> | ||
28 | 29 | ||
29 | #include "zd_def.h" | 30 | #include "zd_def.h" |
30 | #include "zd_chip.h" | 31 | #include "zd_chip.h" |
@@ -755,7 +756,7 @@ static int hw_reset_phy(struct zd_chip *chip) | |||
755 | static int zd1211_hw_init_hmac(struct zd_chip *chip) | 756 | static int zd1211_hw_init_hmac(struct zd_chip *chip) |
756 | { | 757 | { |
757 | static const struct zd_ioreq32 ioreqs[] = { | 758 | static const struct zd_ioreq32 ioreqs[] = { |
758 | { CR_ZD1211_RETRY_MAX, 0x2 }, | 759 | { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT }, |
759 | { CR_RX_THRESHOLD, 0x000c0640 }, | 760 | { CR_RX_THRESHOLD, 0x000c0640 }, |
760 | }; | 761 | }; |
761 | 762 | ||
@@ -767,7 +768,7 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip) | |||
767 | static int zd1211b_hw_init_hmac(struct zd_chip *chip) | 768 | static int zd1211b_hw_init_hmac(struct zd_chip *chip) |
768 | { | 769 | { |
769 | static const struct zd_ioreq32 ioreqs[] = { | 770 | static const struct zd_ioreq32 ioreqs[] = { |
770 | { CR_ZD1211B_RETRY_MAX, 0x02020202 }, | 771 | { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT }, |
771 | { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, | 772 | { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, |
772 | { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, | 773 | { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, |
773 | { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, | 774 | { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, |
@@ -1325,151 +1326,11 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) | |||
1325 | return r; | 1326 | return r; |
1326 | } | 1327 | } |
1327 | 1328 | ||
1328 | static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) | ||
1329 | { | ||
1330 | static const u16 constants[] = { | ||
1331 | 715, 655, 585, 540, 470, 410, 360, 315, | ||
1332 | 270, 235, 205, 175, 150, 125, 105, 85, | ||
1333 | 65, 50, 40, 25, 15 | ||
1334 | }; | ||
1335 | |||
1336 | int i; | ||
1337 | u32 x; | ||
1338 | |||
1339 | /* It seems that their quality parameter is somehow per signal | ||
1340 | * and is now transferred per bit. | ||
1341 | */ | ||
1342 | switch (zd_rate) { | ||
1343 | case ZD_OFDM_RATE_6M: | ||
1344 | case ZD_OFDM_RATE_12M: | ||
1345 | case ZD_OFDM_RATE_24M: | ||
1346 | size *= 2; | ||
1347 | break; | ||
1348 | case ZD_OFDM_RATE_9M: | ||
1349 | case ZD_OFDM_RATE_18M: | ||
1350 | case ZD_OFDM_RATE_36M: | ||
1351 | case ZD_OFDM_RATE_54M: | ||
1352 | size *= 4; | ||
1353 | size /= 3; | ||
1354 | break; | ||
1355 | case ZD_OFDM_RATE_48M: | ||
1356 | size *= 3; | ||
1357 | size /= 2; | ||
1358 | break; | ||
1359 | default: | ||
1360 | return -EINVAL; | ||
1361 | } | ||
1362 | |||
1363 | x = (10000 * status_quality)/size; | ||
1364 | for (i = 0; i < ARRAY_SIZE(constants); i++) { | ||
1365 | if (x > constants[i]) | ||
1366 | break; | ||
1367 | } | ||
1368 | |||
1369 | switch (zd_rate) { | ||
1370 | case ZD_OFDM_RATE_6M: | ||
1371 | case ZD_OFDM_RATE_9M: | ||
1372 | i += 3; | ||
1373 | break; | ||
1374 | case ZD_OFDM_RATE_12M: | ||
1375 | case ZD_OFDM_RATE_18M: | ||
1376 | i += 5; | ||
1377 | break; | ||
1378 | case ZD_OFDM_RATE_24M: | ||
1379 | case ZD_OFDM_RATE_36M: | ||
1380 | i += 9; | ||
1381 | break; | ||
1382 | case ZD_OFDM_RATE_48M: | ||
1383 | case ZD_OFDM_RATE_54M: | ||
1384 | i += 15; | ||
1385 | break; | ||
1386 | default: | ||
1387 | return -EINVAL; | ||
1388 | } | ||
1389 | |||
1390 | return i; | ||
1391 | } | ||
1392 | |||
1393 | static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size) | ||
1394 | { | ||
1395 | int r; | ||
1396 | |||
1397 | r = ofdm_qual_db(status_quality, zd_rate, size); | ||
1398 | ZD_ASSERT(r >= 0); | ||
1399 | if (r < 0) | ||
1400 | r = 0; | ||
1401 | |||
1402 | r = (r * 100)/29; | ||
1403 | return r <= 100 ? r : 100; | ||
1404 | } | ||
1405 | |||
1406 | static unsigned int log10times100(unsigned int x) | ||
1407 | { | ||
1408 | static const u8 log10[] = { | ||
1409 | 0, | ||
1410 | 0, 30, 47, 60, 69, 77, 84, 90, 95, 100, | ||
1411 | 104, 107, 111, 114, 117, 120, 123, 125, 127, 130, | ||
1412 | 132, 134, 136, 138, 139, 141, 143, 144, 146, 147, | ||
1413 | 149, 150, 151, 153, 154, 155, 156, 157, 159, 160, | ||
1414 | 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, | ||
1415 | 170, 171, 172, 173, 174, 174, 175, 176, 177, 177, | ||
1416 | 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, | ||
1417 | 185, 185, 186, 186, 187, 188, 188, 189, 189, 190, | ||
1418 | 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, | ||
1419 | 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, | ||
1420 | 200, 200, 201, 201, 202, 202, 202, 203, 203, 204, | ||
1421 | 204, 204, 205, 205, 206, 206, 206, 207, 207, 207, | ||
1422 | 208, 208, 208, 209, 209, 210, 210, 210, 211, 211, | ||
1423 | 211, 212, 212, 212, 213, 213, 213, 213, 214, 214, | ||
1424 | 214, 215, 215, 215, 216, 216, 216, 217, 217, 217, | ||
1425 | 217, 218, 218, 218, 219, 219, 219, 219, 220, 220, | ||
1426 | 220, 220, 221, 221, 221, 222, 222, 222, 222, 223, | ||
1427 | 223, 223, 223, 224, 224, 224, 224, | ||
1428 | }; | ||
1429 | |||
1430 | return x < ARRAY_SIZE(log10) ? log10[x] : 225; | ||
1431 | } | ||
1432 | |||
1433 | enum { | ||
1434 | MAX_CCK_EVM_DB = 45, | ||
1435 | }; | ||
1436 | |||
1437 | static int cck_evm_db(u8 status_quality) | ||
1438 | { | ||
1439 | return (20 * log10times100(status_quality)) / 100; | ||
1440 | } | ||
1441 | |||
1442 | static int cck_snr_db(u8 status_quality) | ||
1443 | { | ||
1444 | int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality); | ||
1445 | ZD_ASSERT(r >= 0); | ||
1446 | return r; | ||
1447 | } | ||
1448 | |||
1449 | static int cck_qual_percent(u8 status_quality) | ||
1450 | { | ||
1451 | int r; | ||
1452 | |||
1453 | r = cck_snr_db(status_quality); | ||
1454 | r = (100*r)/17; | ||
1455 | return r <= 100 ? r : 100; | ||
1456 | } | ||
1457 | |||
1458 | static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) | 1329 | static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) |
1459 | { | 1330 | { |
1460 | return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); | 1331 | return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); |
1461 | } | 1332 | } |
1462 | 1333 | ||
1463 | u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, | ||
1464 | const struct rx_status *status) | ||
1465 | { | ||
1466 | return (status->frame_status&ZD_RX_OFDM) ? | ||
1467 | ofdm_qual_percent(status->signal_quality_ofdm, | ||
1468 | zd_rate_from_ofdm_plcp_header(rx_frame), | ||
1469 | size) : | ||
1470 | cck_qual_percent(status->signal_quality_cck); | ||
1471 | } | ||
1472 | |||
1473 | /** | 1334 | /** |
1474 | * zd_rx_rate - report zd-rate | 1335 | * zd_rx_rate - report zd-rate |
1475 | * @rx_frame - received frame | 1336 | * @rx_frame - received frame |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 678c139a840c..f8bbf7d302ae 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h | |||
@@ -642,13 +642,29 @@ enum { | |||
642 | #define CR_ZD1211B_TXOP CTL_REG(0x0b20) | 642 | #define CR_ZD1211B_TXOP CTL_REG(0x0b20) |
643 | #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) | 643 | #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) |
644 | 644 | ||
645 | /* Value for CR_ZD1211_RETRY_MAX & CR_ZD1211B_RETRY_MAX. Vendor driver uses 2, | ||
646 | * we use 0. The first rate is tried (count+2), then all next rates are tried | ||
647 | * twice, until 1 Mbits is tried. */ | ||
648 | #define ZD1211_RETRY_COUNT 0 | ||
649 | #define ZD1211B_RETRY_COUNT \ | ||
650 | (ZD1211_RETRY_COUNT << 0)| \ | ||
651 | (ZD1211_RETRY_COUNT << 8)| \ | ||
652 | (ZD1211_RETRY_COUNT << 16)| \ | ||
653 | (ZD1211_RETRY_COUNT << 24) | ||
654 | |||
645 | /* Used to detect PLL lock */ | 655 | /* Used to detect PLL lock */ |
646 | #define UW2453_INTR_REG ((zd_addr_t)0x85c1) | 656 | #define UW2453_INTR_REG ((zd_addr_t)0x85c1) |
647 | 657 | ||
648 | #define CWIN_SIZE 0x007f043f | 658 | #define CWIN_SIZE 0x007f043f |
649 | 659 | ||
650 | 660 | ||
651 | #define HWINT_ENABLED 0x004f0000 | 661 | #define HWINT_ENABLED \ |
662 | (INT_TX_COMPLETE_EN| \ | ||
663 | INT_RX_COMPLETE_EN| \ | ||
664 | INT_RETRY_FAIL_EN| \ | ||
665 | INT_WAKEUP_EN| \ | ||
666 | INT_CFG_NEXT_BCN_EN) | ||
667 | |||
652 | #define HWINT_DISABLED 0 | 668 | #define HWINT_DISABLED 0 |
653 | 669 | ||
654 | #define E2P_PWR_INT_GUARD 8 | 670 | #define E2P_PWR_INT_GUARD 8 |
@@ -913,9 +929,6 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) | |||
913 | 929 | ||
914 | struct rx_status; | 930 | struct rx_status; |
915 | 931 | ||
916 | u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, | ||
917 | const struct rx_status *status); | ||
918 | |||
919 | u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status); | 932 | u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status); |
920 | 933 | ||
921 | struct zd_mc_hash { | 934 | struct zd_mc_hash { |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6d666359a42f..16fa289ad77b 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
24 | #include <linux/etherdevice.h> | 24 | #include <linux/etherdevice.h> |
25 | #include <linux/slab.h> | ||
25 | #include <linux/usb.h> | 26 | #include <linux/usb.h> |
26 | #include <linux/jiffies.h> | 27 | #include <linux/jiffies.h> |
27 | #include <net/ieee80211_radiotap.h> | 28 | #include <net/ieee80211_radiotap.h> |
@@ -88,6 +89,34 @@ static const struct ieee80211_rate zd_rates[] = { | |||
88 | .flags = 0 }, | 89 | .flags = 0 }, |
89 | }; | 90 | }; |
90 | 91 | ||
92 | /* | ||
93 | * Zydas retry rates table. Each line is listed in the same order as | ||
94 | * in zd_rates[] and contains all the rate used when a packet is sent | ||
95 | * starting with a given rates. Let's consider an example : | ||
96 | * | ||
97 | * "11 Mbits : 4, 3, 2, 1, 0" means : | ||
98 | * - packet is sent using 4 different rates | ||
99 | * - 1st rate is index 3 (ie 11 Mbits) | ||
100 | * - 2nd rate is index 2 (ie 5.5 Mbits) | ||
101 | * - 3rd rate is index 1 (ie 2 Mbits) | ||
102 | * - 4th rate is index 0 (ie 1 Mbits) | ||
103 | */ | ||
104 | |||
105 | static const struct tx_retry_rate zd_retry_rates[] = { | ||
106 | { /* 1 Mbits */ 1, { 0 }}, | ||
107 | { /* 2 Mbits */ 2, { 1, 0 }}, | ||
108 | { /* 5.5 Mbits */ 3, { 2, 1, 0 }}, | ||
109 | { /* 11 Mbits */ 4, { 3, 2, 1, 0 }}, | ||
110 | { /* 6 Mbits */ 5, { 4, 3, 2, 1, 0 }}, | ||
111 | { /* 9 Mbits */ 6, { 5, 4, 3, 2, 1, 0}}, | ||
112 | { /* 12 Mbits */ 5, { 6, 3, 2, 1, 0 }}, | ||
113 | { /* 18 Mbits */ 6, { 7, 6, 3, 2, 1, 0 }}, | ||
114 | { /* 24 Mbits */ 6, { 8, 6, 3, 2, 1, 0 }}, | ||
115 | { /* 36 Mbits */ 7, { 9, 8, 6, 3, 2, 1, 0 }}, | ||
116 | { /* 48 Mbits */ 8, {10, 9, 8, 6, 3, 2, 1, 0 }}, | ||
117 | { /* 54 Mbits */ 9, {11, 10, 9, 8, 6, 3, 2, 1, 0 }} | ||
118 | }; | ||
119 | |||
91 | static const struct ieee80211_channel zd_channels[] = { | 120 | static const struct ieee80211_channel zd_channels[] = { |
92 | { .center_freq = 2412, .hw_value = 1 }, | 121 | { .center_freq = 2412, .hw_value = 1 }, |
93 | { .center_freq = 2417, .hw_value = 2 }, | 122 | { .center_freq = 2417, .hw_value = 2 }, |
@@ -282,7 +311,7 @@ static void zd_op_stop(struct ieee80211_hw *hw) | |||
282 | } | 311 | } |
283 | 312 | ||
284 | /** | 313 | /** |
285 | * tx_status - reports tx status of a packet if required | 314 | * zd_mac_tx_status - reports tx status of a packet if required |
286 | * @hw - a &struct ieee80211_hw pointer | 315 | * @hw - a &struct ieee80211_hw pointer |
287 | * @skb - a sk-buffer | 316 | * @skb - a sk-buffer |
288 | * @flags: extra flags to set in the TX status info | 317 | * @flags: extra flags to set in the TX status info |
@@ -295,15 +324,49 @@ static void zd_op_stop(struct ieee80211_hw *hw) | |||
295 | * | 324 | * |
296 | * If no status information has been requested, the skb is freed. | 325 | * If no status information has been requested, the skb is freed. |
297 | */ | 326 | */ |
298 | static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | 327 | static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, |
299 | int ackssi, bool success) | 328 | int ackssi, struct tx_status *tx_status) |
300 | { | 329 | { |
301 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 330 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
331 | int i; | ||
332 | int success = 1, retry = 1; | ||
333 | int first_idx; | ||
334 | const struct tx_retry_rate *retries; | ||
302 | 335 | ||
303 | ieee80211_tx_info_clear_status(info); | 336 | ieee80211_tx_info_clear_status(info); |
304 | 337 | ||
305 | if (success) | 338 | if (tx_status) { |
339 | success = !tx_status->failure; | ||
340 | retry = tx_status->retry + success; | ||
341 | } | ||
342 | |||
343 | if (success) { | ||
344 | /* success */ | ||
306 | info->flags |= IEEE80211_TX_STAT_ACK; | 345 | info->flags |= IEEE80211_TX_STAT_ACK; |
346 | } else { | ||
347 | /* failure */ | ||
348 | info->flags &= ~IEEE80211_TX_STAT_ACK; | ||
349 | } | ||
350 | |||
351 | first_idx = info->status.rates[0].idx; | ||
352 | ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); | ||
353 | retries = &zd_retry_rates[first_idx]; | ||
354 | ZD_ASSERT(1 <= retry && retry <= retries->count); | ||
355 | |||
356 | info->status.rates[0].idx = retries->rate[0]; | ||
357 | info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1); | ||
358 | |||
359 | for (i=1; i<IEEE80211_TX_MAX_RATES-1 && i<retry; i++) { | ||
360 | info->status.rates[i].idx = retries->rate[i]; | ||
361 | info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2); | ||
362 | } | ||
363 | for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) { | ||
364 | info->status.rates[i].idx = retries->rate[retry - 1]; | ||
365 | info->status.rates[i].count = 1; // (success ? 1:2); | ||
366 | } | ||
367 | if (i<IEEE80211_TX_MAX_RATES) | ||
368 | info->status.rates[i].idx = -1; /* terminate */ | ||
369 | |||
307 | info->status.ack_signal = ackssi; | 370 | info->status.ack_signal = ackssi; |
308 | ieee80211_tx_status_irqsafe(hw, skb); | 371 | ieee80211_tx_status_irqsafe(hw, skb); |
309 | } | 372 | } |
@@ -312,20 +375,81 @@ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
312 | * zd_mac_tx_failed - callback for failed frames | 375 | * zd_mac_tx_failed - callback for failed frames |
313 | * @dev: the mac80211 wireless device | 376 | * @dev: the mac80211 wireless device |
314 | * | 377 | * |
315 | * This function is called if a frame couldn't be succesfully be | 378 | * This function is called if a frame couldn't be successfully |
316 | * transferred. The first frame from the tx queue, will be selected and | 379 | * transferred. The first frame from the tx queue, will be selected and |
317 | * reported as error to the upper layers. | 380 | * reported as error to the upper layers. |
318 | */ | 381 | */ |
319 | void zd_mac_tx_failed(struct ieee80211_hw *hw) | 382 | void zd_mac_tx_failed(struct urb *urb) |
320 | { | 383 | { |
321 | struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; | 384 | struct ieee80211_hw * hw = zd_usb_to_hw(urb->context); |
385 | struct zd_mac *mac = zd_hw_mac(hw); | ||
386 | struct sk_buff_head *q = &mac->ack_wait_queue; | ||
322 | struct sk_buff *skb; | 387 | struct sk_buff *skb; |
388 | struct tx_status *tx_status = (struct tx_status *)urb->transfer_buffer; | ||
389 | unsigned long flags; | ||
390 | int success = !tx_status->failure; | ||
391 | int retry = tx_status->retry + success; | ||
392 | int found = 0; | ||
393 | int i, position = 0; | ||
323 | 394 | ||
324 | skb = skb_dequeue(q); | 395 | q = &mac->ack_wait_queue; |
325 | if (skb == NULL) | 396 | spin_lock_irqsave(&q->lock, flags); |
326 | return; | 397 | |
398 | skb_queue_walk(q, skb) { | ||
399 | struct ieee80211_hdr *tx_hdr; | ||
400 | struct ieee80211_tx_info *info; | ||
401 | int first_idx, final_idx; | ||
402 | const struct tx_retry_rate *retries; | ||
403 | u8 final_rate; | ||
404 | |||
405 | position ++; | ||
406 | |||
407 | /* if the hardware reports a failure and we had a 802.11 ACK | ||
408 | * pending, then we skip the first skb when searching for a | ||
409 | * matching frame */ | ||
410 | if (tx_status->failure && mac->ack_pending && | ||
411 | skb_queue_is_first(q, skb)) { | ||
412 | continue; | ||
413 | } | ||
414 | |||
415 | tx_hdr = (struct ieee80211_hdr *)skb->data; | ||
416 | |||
417 | /* we skip all frames not matching the reported destination */ | ||
418 | if (unlikely(memcmp(tx_hdr->addr1, tx_status->mac, ETH_ALEN))) { | ||
419 | continue; | ||
420 | } | ||
421 | |||
422 | /* we skip all frames not matching the reported final rate */ | ||
423 | |||
424 | info = IEEE80211_SKB_CB(skb); | ||
425 | first_idx = info->status.rates[0].idx; | ||
426 | ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); | ||
427 | retries = &zd_retry_rates[first_idx]; | ||
428 | if (retry <= 0 || retry > retries->count) | ||
429 | continue; | ||
430 | |||
431 | final_idx = retries->rate[retry - 1]; | ||
432 | final_rate = zd_rates[final_idx].hw_value; | ||
327 | 433 | ||
328 | tx_status(hw, skb, 0, 0); | 434 | if (final_rate != tx_status->rate) { |
435 | continue; | ||
436 | } | ||
437 | |||
438 | found = 1; | ||
439 | break; | ||
440 | } | ||
441 | |||
442 | if (found) { | ||
443 | for (i=1; i<=position; i++) { | ||
444 | skb = __skb_dequeue(q); | ||
445 | zd_mac_tx_status(hw, skb, | ||
446 | mac->ack_pending ? mac->ack_signal : 0, | ||
447 | i == position ? tx_status : NULL); | ||
448 | mac->ack_pending = 0; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | spin_unlock_irqrestore(&q->lock, flags); | ||
329 | } | 453 | } |
330 | 454 | ||
331 | /** | 455 | /** |
@@ -342,18 +466,27 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) | |||
342 | { | 466 | { |
343 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 467 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
344 | struct ieee80211_hw *hw = info->rate_driver_data[0]; | 468 | struct ieee80211_hw *hw = info->rate_driver_data[0]; |
469 | struct zd_mac *mac = zd_hw_mac(hw); | ||
470 | |||
471 | ieee80211_tx_info_clear_status(info); | ||
345 | 472 | ||
346 | skb_pull(skb, sizeof(struct zd_ctrlset)); | 473 | skb_pull(skb, sizeof(struct zd_ctrlset)); |
347 | if (unlikely(error || | 474 | if (unlikely(error || |
348 | (info->flags & IEEE80211_TX_CTL_NO_ACK))) { | 475 | (info->flags & IEEE80211_TX_CTL_NO_ACK))) { |
349 | tx_status(hw, skb, 0, !error); | 476 | /* |
477 | * FIXME : do we need to fill in anything ? | ||
478 | */ | ||
479 | ieee80211_tx_status_irqsafe(hw, skb); | ||
350 | } else { | 480 | } else { |
351 | struct sk_buff_head *q = | 481 | struct sk_buff_head *q = &mac->ack_wait_queue; |
352 | &zd_hw_mac(hw)->ack_wait_queue; | ||
353 | 482 | ||
354 | skb_queue_tail(q, skb); | 483 | skb_queue_tail(q, skb); |
355 | while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) | 484 | while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) { |
356 | zd_mac_tx_failed(hw); | 485 | zd_mac_tx_status(hw, skb_dequeue(q), |
486 | mac->ack_pending ? mac->ack_signal : 0, | ||
487 | NULL); | ||
488 | mac->ack_pending = 0; | ||
489 | } | ||
357 | } | 490 | } |
358 | } | 491 | } |
359 | 492 | ||
@@ -606,27 +739,47 @@ fail: | |||
606 | static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, | 739 | static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, |
607 | struct ieee80211_rx_status *stats) | 740 | struct ieee80211_rx_status *stats) |
608 | { | 741 | { |
742 | struct zd_mac *mac = zd_hw_mac(hw); | ||
609 | struct sk_buff *skb; | 743 | struct sk_buff *skb; |
610 | struct sk_buff_head *q; | 744 | struct sk_buff_head *q; |
611 | unsigned long flags; | 745 | unsigned long flags; |
746 | int found = 0; | ||
747 | int i, position = 0; | ||
612 | 748 | ||
613 | if (!ieee80211_is_ack(rx_hdr->frame_control)) | 749 | if (!ieee80211_is_ack(rx_hdr->frame_control)) |
614 | return 0; | 750 | return 0; |
615 | 751 | ||
616 | q = &zd_hw_mac(hw)->ack_wait_queue; | 752 | q = &mac->ack_wait_queue; |
617 | spin_lock_irqsave(&q->lock, flags); | 753 | spin_lock_irqsave(&q->lock, flags); |
618 | skb_queue_walk(q, skb) { | 754 | skb_queue_walk(q, skb) { |
619 | struct ieee80211_hdr *tx_hdr; | 755 | struct ieee80211_hdr *tx_hdr; |
620 | 756 | ||
757 | position ++; | ||
758 | |||
759 | if (mac->ack_pending && skb_queue_is_first(q, skb)) | ||
760 | continue; | ||
761 | |||
621 | tx_hdr = (struct ieee80211_hdr *)skb->data; | 762 | tx_hdr = (struct ieee80211_hdr *)skb->data; |
622 | if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) | 763 | if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) |
623 | { | 764 | { |
624 | __skb_unlink(skb, q); | 765 | found = 1; |
625 | tx_status(hw, skb, stats->signal, 1); | 766 | break; |
626 | goto out; | ||
627 | } | 767 | } |
628 | } | 768 | } |
629 | out: | 769 | |
770 | if (found) { | ||
771 | for (i=1; i<position; i++) { | ||
772 | skb = __skb_dequeue(q); | ||
773 | zd_mac_tx_status(hw, skb, | ||
774 | mac->ack_pending ? mac->ack_signal : 0, | ||
775 | NULL); | ||
776 | mac->ack_pending = 0; | ||
777 | } | ||
778 | |||
779 | mac->ack_pending = 1; | ||
780 | mac->ack_signal = stats->signal; | ||
781 | } | ||
782 | |||
630 | spin_unlock_irqrestore(&q->lock, flags); | 783 | spin_unlock_irqrestore(&q->lock, flags); |
631 | return 1; | 784 | return 1; |
632 | } | 785 | } |
@@ -674,9 +827,6 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) | |||
674 | stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; | 827 | stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; |
675 | stats.band = IEEE80211_BAND_2GHZ; | 828 | stats.band = IEEE80211_BAND_2GHZ; |
676 | stats.signal = status->signal_strength; | 829 | stats.signal = status->signal_strength; |
677 | stats.qual = zd_rx_qual_percent(buffer, | ||
678 | length - sizeof(struct rx_status), | ||
679 | status); | ||
680 | 830 | ||
681 | rate = zd_rx_rate(buffer, status); | 831 | rate = zd_rx_rate(buffer, status); |
682 | 832 | ||
@@ -709,6 +859,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) | |||
709 | skb_reserve(skb, 2); | 859 | skb_reserve(skb, 2); |
710 | } | 860 | } |
711 | 861 | ||
862 | /* FIXME : could we avoid this big memcpy ? */ | ||
712 | memcpy(skb_put(skb, length), buffer, length); | 863 | memcpy(skb_put(skb, length), buffer, length); |
713 | 864 | ||
714 | memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); | 865 | memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); |
@@ -717,7 +868,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) | |||
717 | } | 868 | } |
718 | 869 | ||
719 | static int zd_op_add_interface(struct ieee80211_hw *hw, | 870 | static int zd_op_add_interface(struct ieee80211_hw *hw, |
720 | struct ieee80211_if_init_conf *conf) | 871 | struct ieee80211_vif *vif) |
721 | { | 872 | { |
722 | struct zd_mac *mac = zd_hw_mac(hw); | 873 | struct zd_mac *mac = zd_hw_mac(hw); |
723 | 874 | ||
@@ -725,22 +876,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, | |||
725 | if (mac->type != NL80211_IFTYPE_UNSPECIFIED) | 876 | if (mac->type != NL80211_IFTYPE_UNSPECIFIED) |
726 | return -EOPNOTSUPP; | 877 | return -EOPNOTSUPP; |
727 | 878 | ||
728 | switch (conf->type) { | 879 | switch (vif->type) { |
729 | case NL80211_IFTYPE_MONITOR: | 880 | case NL80211_IFTYPE_MONITOR: |
730 | case NL80211_IFTYPE_MESH_POINT: | 881 | case NL80211_IFTYPE_MESH_POINT: |
731 | case NL80211_IFTYPE_STATION: | 882 | case NL80211_IFTYPE_STATION: |
732 | case NL80211_IFTYPE_ADHOC: | 883 | case NL80211_IFTYPE_ADHOC: |
733 | mac->type = conf->type; | 884 | mac->type = vif->type; |
734 | break; | 885 | break; |
735 | default: | 886 | default: |
736 | return -EOPNOTSUPP; | 887 | return -EOPNOTSUPP; |
737 | } | 888 | } |
738 | 889 | ||
739 | return zd_write_mac_addr(&mac->chip, conf->mac_addr); | 890 | return zd_write_mac_addr(&mac->chip, vif->addr); |
740 | } | 891 | } |
741 | 892 | ||
742 | static void zd_op_remove_interface(struct ieee80211_hw *hw, | 893 | static void zd_op_remove_interface(struct ieee80211_hw *hw, |
743 | struct ieee80211_if_init_conf *conf) | 894 | struct ieee80211_vif *vif) |
744 | { | 895 | { |
745 | struct zd_mac *mac = zd_hw_mac(hw); | 896 | struct zd_mac *mac = zd_hw_mac(hw); |
746 | mac->type = NL80211_IFTYPE_UNSPECIFIED; | 897 | mac->type = NL80211_IFTYPE_UNSPECIFIED; |
@@ -835,12 +986,13 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
835 | changed_flags &= SUPPORTED_FIF_FLAGS; | 986 | changed_flags &= SUPPORTED_FIF_FLAGS; |
836 | *new_flags &= SUPPORTED_FIF_FLAGS; | 987 | *new_flags &= SUPPORTED_FIF_FLAGS; |
837 | 988 | ||
838 | /* changed_flags is always populated but this driver | 989 | /* |
839 | * doesn't support all FIF flags so its possible we don't | 990 | * If multicast parameter (as returned by zd_op_prepare_multicast) |
840 | * need to do anything */ | 991 | * has changed, no bit in changed_flags is set. To handle this |
841 | if (!changed_flags) | 992 | * situation, we do not return if changed_flags is 0. If we do so, |
842 | return; | 993 | * we will have some issue with IPv6 which uses multicast for link |
843 | 994 | * layer address resolution. | |
995 | */ | ||
844 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) | 996 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) |
845 | zd_mc_add_all(&hash); | 997 | zd_mc_add_all(&hash); |
846 | 998 | ||
@@ -999,7 +1151,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
999 | hw->queues = 1; | 1151 | hw->queues = 1; |
1000 | hw->extra_tx_headroom = sizeof(struct zd_ctrlset); | 1152 | hw->extra_tx_headroom = sizeof(struct zd_ctrlset); |
1001 | 1153 | ||
1154 | /* | ||
1155 | * Tell mac80211 that we support multi rate retries | ||
1156 | */ | ||
1157 | hw->max_rates = IEEE80211_TX_MAX_RATES; | ||
1158 | hw->max_rate_tries = 18; /* 9 rates * 2 retries/rate */ | ||
1159 | |||
1002 | skb_queue_head_init(&mac->ack_wait_queue); | 1160 | skb_queue_head_init(&mac->ack_wait_queue); |
1161 | mac->ack_pending = 0; | ||
1003 | 1162 | ||
1004 | zd_chip_init(&mac->chip, hw, intf); | 1163 | zd_chip_init(&mac->chip, hw, intf); |
1005 | housekeeping_init(mac); | 1164 | housekeeping_init(mac); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 7c2759118d13..630c298a730e 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h | |||
@@ -140,6 +140,21 @@ struct rx_status { | |||
140 | #define ZD_RX_CRC16_ERROR 0x40 | 140 | #define ZD_RX_CRC16_ERROR 0x40 |
141 | #define ZD_RX_ERROR 0x80 | 141 | #define ZD_RX_ERROR 0x80 |
142 | 142 | ||
143 | struct tx_retry_rate { | ||
144 | int count; /* number of valid element in rate[] array */ | ||
145 | int rate[10]; /* retry rates, described by an index in zd_rates[] */ | ||
146 | }; | ||
147 | |||
148 | struct tx_status { | ||
149 | u8 type; /* must always be 0x01 : USB_INT_TYPE */ | ||
150 | u8 id; /* must always be 0xa0 : USB_INT_ID_RETRY_FAILED */ | ||
151 | u8 rate; | ||
152 | u8 pad; | ||
153 | u8 mac[ETH_ALEN]; | ||
154 | u8 retry; | ||
155 | u8 failure; | ||
156 | } __attribute__((packed)); | ||
157 | |||
143 | enum mac_flags { | 158 | enum mac_flags { |
144 | MAC_FIXED_CHANNEL = 0x01, | 159 | MAC_FIXED_CHANNEL = 0x01, |
145 | }; | 160 | }; |
@@ -150,7 +165,7 @@ struct housekeeping { | |||
150 | 165 | ||
151 | #define ZD_MAC_STATS_BUFFER_SIZE 16 | 166 | #define ZD_MAC_STATS_BUFFER_SIZE 16 |
152 | 167 | ||
153 | #define ZD_MAC_MAX_ACK_WAITERS 10 | 168 | #define ZD_MAC_MAX_ACK_WAITERS 50 |
154 | 169 | ||
155 | struct zd_mac { | 170 | struct zd_mac { |
156 | struct zd_chip chip; | 171 | struct zd_chip chip; |
@@ -184,6 +199,12 @@ struct zd_mac { | |||
184 | 199 | ||
185 | /* whether to pass control frames to stack */ | 200 | /* whether to pass control frames to stack */ |
186 | unsigned int pass_ctrl:1; | 201 | unsigned int pass_ctrl:1; |
202 | |||
203 | /* whether we have received a 802.11 ACK that is pending */ | ||
204 | unsigned int ack_pending:1; | ||
205 | |||
206 | /* signal strength of the last 802.11 ACK received */ | ||
207 | int ack_signal; | ||
187 | }; | 208 | }; |
188 | 209 | ||
189 | #define ZD_REGDOMAIN_FCC 0x10 | 210 | #define ZD_REGDOMAIN_FCC 0x10 |
@@ -279,7 +300,7 @@ int zd_mac_preinit_hw(struct ieee80211_hw *hw); | |||
279 | int zd_mac_init_hw(struct ieee80211_hw *hw); | 300 | int zd_mac_init_hw(struct ieee80211_hw *hw); |
280 | 301 | ||
281 | int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); | 302 | int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); |
282 | void zd_mac_tx_failed(struct ieee80211_hw *hw); | 303 | void zd_mac_tx_failed(struct urb *urb); |
283 | void zd_mac_tx_to_dev(struct sk_buff *skb, int error); | 304 | void zd_mac_tx_to_dev(struct sk_buff *skb, int error); |
284 | 305 | ||
285 | #ifdef DEBUG | 306 | #ifdef DEBUG |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index 439799b84876..9e74eb1b67d5 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c | |||
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/slab.h> | ||
22 | 23 | ||
23 | #include "zd_rf.h" | 24 | #include "zd_rf.h" |
24 | #include "zd_usb.h" | 25 | #include "zd_usb.h" |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 23a6a6d4863b..d91ad1a612af 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
27 | #include <linux/slab.h> | ||
27 | #include <linux/skbuff.h> | 28 | #include <linux/skbuff.h> |
28 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
29 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
@@ -62,6 +63,7 @@ static struct usb_device_id usb_ids[] = { | |||
62 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, | 63 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, |
63 | /* ZD1211B */ | 64 | /* ZD1211B */ |
64 | { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, | 65 | { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, |
66 | { USB_DEVICE(0x0409, 0x0248), .driver_info = DEVICE_ZD1211B }, | ||
65 | { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, | 67 | { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, |
66 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, | 68 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, |
67 | { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, | 69 | { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, |
@@ -318,6 +320,13 @@ error: | |||
318 | return r; | 320 | return r; |
319 | } | 321 | } |
320 | 322 | ||
323 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); | ||
324 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); | ||
325 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); | ||
326 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); | ||
327 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); | ||
328 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); | ||
329 | |||
321 | /* Read data from device address space using "firmware interface" which does | 330 | /* Read data from device address space using "firmware interface" which does |
322 | * not require firmware to be loaded. */ | 331 | * not require firmware to be loaded. */ |
323 | int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) | 332 | int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) |
@@ -419,7 +428,7 @@ static void int_urb_complete(struct urb *urb) | |||
419 | handle_regs_int(urb); | 428 | handle_regs_int(urb); |
420 | break; | 429 | break; |
421 | case USB_INT_ID_RETRY_FAILED: | 430 | case USB_INT_ID_RETRY_FAILED: |
422 | zd_mac_tx_failed(zd_usb_to_hw(urb->context)); | 431 | zd_mac_tx_failed(urb); |
423 | break; | 432 | break; |
424 | default: | 433 | default: |
425 | dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, | 434 | dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, |
@@ -553,6 +562,8 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, | |||
553 | 562 | ||
554 | if (length < sizeof(struct rx_length_info)) { | 563 | if (length < sizeof(struct rx_length_info)) { |
555 | /* It's not a complete packet anyhow. */ | 564 | /* It's not a complete packet anyhow. */ |
565 | printk("%s: invalid, small RX packet : %d\n", | ||
566 | __func__, length); | ||
556 | return; | 567 | return; |
557 | } | 568 | } |
558 | length_info = (struct rx_length_info *) | 569 | length_info = (struct rx_length_info *) |
@@ -1069,11 +1080,15 @@ static int eject_installer(struct usb_interface *intf) | |||
1069 | int r; | 1080 | int r; |
1070 | 1081 | ||
1071 | /* Find bulk out endpoint */ | 1082 | /* Find bulk out endpoint */ |
1072 | endpoint = &iface_desc->endpoint[1].desc; | 1083 | for (r = 1; r >= 0; r--) { |
1073 | if (usb_endpoint_dir_out(endpoint) && | 1084 | endpoint = &iface_desc->endpoint[r].desc; |
1074 | usb_endpoint_xfer_bulk(endpoint)) { | 1085 | if (usb_endpoint_dir_out(endpoint) && |
1075 | bulk_out_ep = endpoint->bEndpointAddress; | 1086 | usb_endpoint_xfer_bulk(endpoint)) { |
1076 | } else { | 1087 | bulk_out_ep = endpoint->bEndpointAddress; |
1088 | break; | ||
1089 | } | ||
1090 | } | ||
1091 | if (r == -1) { | ||
1077 | dev_err(&udev->dev, | 1092 | dev_err(&udev->dev, |
1078 | "zd1211rw: Could not find bulk out endpoint\n"); | 1093 | "zd1211rw: Could not find bulk out endpoint\n"); |
1079 | return -ENODEV; | 1094 | return -ENODEV; |