diff options
Diffstat (limited to 'drivers/net/wireless/orinoco/main.c')
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 167 |
1 files changed, 116 insertions, 51 deletions
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ebf92ae6e365..cd1c04d42b6a 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -206,6 +206,13 @@ struct orinoco_rx_data { | |||
206 | struct list_head list; | 206 | struct list_head list; |
207 | }; | 207 | }; |
208 | 208 | ||
209 | struct orinoco_scan_data { | ||
210 | void *buf; | ||
211 | size_t len; | ||
212 | int type; | ||
213 | struct list_head list; | ||
214 | }; | ||
215 | |||
209 | /********************************************************************/ | 216 | /********************************************************************/ |
210 | /* Function prototypes */ | 217 | /* Function prototypes */ |
211 | /********************************************************************/ | 218 | /********************************************************************/ |
@@ -1265,6 +1272,78 @@ static void orinoco_send_wevents(struct work_struct *work) | |||
1265 | orinoco_unlock(priv, &flags); | 1272 | orinoco_unlock(priv, &flags); |
1266 | } | 1273 | } |
1267 | 1274 | ||
1275 | static void qbuf_scan(struct orinoco_private *priv, void *buf, | ||
1276 | int len, int type) | ||
1277 | { | ||
1278 | struct orinoco_scan_data *sd; | ||
1279 | unsigned long flags; | ||
1280 | |||
1281 | sd = kmalloc(sizeof(*sd), GFP_ATOMIC); | ||
1282 | sd->buf = buf; | ||
1283 | sd->len = len; | ||
1284 | sd->type = type; | ||
1285 | |||
1286 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1287 | list_add_tail(&sd->list, &priv->scan_list); | ||
1288 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1289 | |||
1290 | schedule_work(&priv->process_scan); | ||
1291 | } | ||
1292 | |||
1293 | static void qabort_scan(struct orinoco_private *priv) | ||
1294 | { | ||
1295 | struct orinoco_scan_data *sd; | ||
1296 | unsigned long flags; | ||
1297 | |||
1298 | sd = kmalloc(sizeof(*sd), GFP_ATOMIC); | ||
1299 | sd->len = -1; /* Abort */ | ||
1300 | |||
1301 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1302 | list_add_tail(&sd->list, &priv->scan_list); | ||
1303 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1304 | |||
1305 | schedule_work(&priv->process_scan); | ||
1306 | } | ||
1307 | |||
1308 | static void orinoco_process_scan_results(struct work_struct *work) | ||
1309 | { | ||
1310 | struct orinoco_private *priv = | ||
1311 | container_of(work, struct orinoco_private, process_scan); | ||
1312 | struct orinoco_scan_data *sd, *temp; | ||
1313 | unsigned long flags; | ||
1314 | void *buf; | ||
1315 | int len; | ||
1316 | int type; | ||
1317 | |||
1318 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1319 | list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { | ||
1320 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1321 | |||
1322 | buf = sd->buf; | ||
1323 | len = sd->len; | ||
1324 | type = sd->type; | ||
1325 | |||
1326 | list_del(&sd->list); | ||
1327 | kfree(sd); | ||
1328 | |||
1329 | if (len > 0) { | ||
1330 | if (type == HERMES_INQ_CHANNELINFO) | ||
1331 | orinoco_add_extscan_result(priv, buf, len); | ||
1332 | else | ||
1333 | orinoco_add_hostscan_results(priv, buf, len); | ||
1334 | |||
1335 | kfree(buf); | ||
1336 | } else if (priv->scan_request) { | ||
1337 | /* Either abort or complete the scan */ | ||
1338 | cfg80211_scan_done(priv->scan_request, (len < 0)); | ||
1339 | priv->scan_request = NULL; | ||
1340 | } | ||
1341 | |||
1342 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1343 | } | ||
1344 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1345 | } | ||
1346 | |||
1268 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | 1347 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) |
1269 | { | 1348 | { |
1270 | struct orinoco_private *priv = ndev_priv(dev); | 1349 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -1351,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1351 | * the hostscan frame can be requested. */ | 1430 | * the hostscan frame can be requested. */ |
1352 | if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && | 1431 | if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && |
1353 | priv->firmware_type == FIRMWARE_TYPE_SYMBOL && | 1432 | priv->firmware_type == FIRMWARE_TYPE_SYMBOL && |
1354 | priv->has_hostscan && priv->scan_inprogress) { | 1433 | priv->has_hostscan && priv->scan_request) { |
1355 | hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); | 1434 | hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); |
1356 | break; | 1435 | break; |
1357 | } | 1436 | } |
@@ -1377,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1377 | } | 1456 | } |
1378 | break; | 1457 | break; |
1379 | case HERMES_INQ_SCAN: | 1458 | case HERMES_INQ_SCAN: |
1380 | if (!priv->scan_inprogress && priv->bssid_fixed && | 1459 | if (!priv->scan_request && priv->bssid_fixed && |
1381 | priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { | 1460 | priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { |
1382 | schedule_work(&priv->join_work); | 1461 | schedule_work(&priv->join_work); |
1383 | break; | 1462 | break; |
@@ -1387,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1387 | case HERMES_INQ_HOSTSCAN_SYMBOL: { | 1466 | case HERMES_INQ_HOSTSCAN_SYMBOL: { |
1388 | /* Result of a scanning. Contains information about | 1467 | /* Result of a scanning. Contains information about |
1389 | * cells in the vicinity - Jean II */ | 1468 | * cells in the vicinity - Jean II */ |
1390 | union iwreq_data wrqu; | ||
1391 | unsigned char *buf; | 1469 | unsigned char *buf; |
1392 | 1470 | ||
1393 | /* Scan is no longer in progress */ | ||
1394 | priv->scan_inprogress = 0; | ||
1395 | |||
1396 | /* Sanity check */ | 1471 | /* Sanity check */ |
1397 | if (len > 4096) { | 1472 | if (len > 4096) { |
1398 | printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", | 1473 | printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", |
1399 | dev->name, len); | 1474 | dev->name, len); |
1475 | qabort_scan(priv); | ||
1400 | break; | 1476 | break; |
1401 | } | 1477 | } |
1402 | 1478 | ||
1403 | /* Allocate buffer for results */ | 1479 | /* Allocate buffer for results */ |
1404 | buf = kmalloc(len, GFP_ATOMIC); | 1480 | buf = kmalloc(len, GFP_ATOMIC); |
1405 | if (buf == NULL) | 1481 | if (buf == NULL) { |
1406 | /* No memory, so can't printk()... */ | 1482 | /* No memory, so can't printk()... */ |
1483 | qabort_scan(priv); | ||
1407 | break; | 1484 | break; |
1485 | } | ||
1408 | 1486 | ||
1409 | /* Read scan data */ | 1487 | /* Read scan data */ |
1410 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, | 1488 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, |
1411 | infofid, sizeof(info)); | 1489 | infofid, sizeof(info)); |
1412 | if (err) { | 1490 | if (err) { |
1413 | kfree(buf); | 1491 | kfree(buf); |
1492 | qabort_scan(priv); | ||
1414 | break; | 1493 | break; |
1415 | } | 1494 | } |
1416 | 1495 | ||
@@ -1424,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1424 | } | 1503 | } |
1425 | #endif /* ORINOCO_DEBUG */ | 1504 | #endif /* ORINOCO_DEBUG */ |
1426 | 1505 | ||
1427 | if (orinoco_process_scan_results(priv, buf, len) == 0) { | 1506 | qbuf_scan(priv, buf, len, type); |
1428 | /* Send an empty event to user space. | ||
1429 | * We don't send the received data on the event because | ||
1430 | * it would require us to do complex transcoding, and | ||
1431 | * we want to minimise the work done in the irq handler | ||
1432 | * Use a request to extract the data - Jean II */ | ||
1433 | wrqu.data.length = 0; | ||
1434 | wrqu.data.flags = 0; | ||
1435 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
1436 | } | ||
1437 | kfree(buf); | ||
1438 | } | 1507 | } |
1439 | break; | 1508 | break; |
1440 | case HERMES_INQ_CHANNELINFO: | 1509 | case HERMES_INQ_CHANNELINFO: |
1441 | { | 1510 | { |
1442 | struct agere_ext_scan_info *bss; | 1511 | struct agere_ext_scan_info *bss; |
1443 | 1512 | ||
1444 | if (!priv->scan_inprogress) { | 1513 | if (!priv->scan_request) { |
1445 | printk(KERN_DEBUG "%s: Got chaninfo without scan, " | 1514 | printk(KERN_DEBUG "%s: Got chaninfo without scan, " |
1446 | "len=%d\n", dev->name, len); | 1515 | "len=%d\n", dev->name, len); |
1447 | break; | 1516 | break; |
@@ -1449,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1449 | 1518 | ||
1450 | /* An empty result indicates that the scan is complete */ | 1519 | /* An empty result indicates that the scan is complete */ |
1451 | if (len == 0) { | 1520 | if (len == 0) { |
1452 | union iwreq_data wrqu; | 1521 | qbuf_scan(priv, NULL, len, type); |
1453 | |||
1454 | /* Scan is no longer in progress */ | ||
1455 | priv->scan_inprogress = 0; | ||
1456 | |||
1457 | wrqu.data.length = 0; | ||
1458 | wrqu.data.flags = 0; | ||
1459 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
1460 | break; | 1522 | break; |
1461 | } | 1523 | } |
1462 | 1524 | ||
1463 | /* Sanity check */ | 1525 | /* Sanity check */ |
1464 | else if (len > sizeof(*bss)) { | 1526 | else if (len < (offsetof(struct agere_ext_scan_info, |
1465 | printk(KERN_WARNING | ||
1466 | "%s: Ext scan results too large (%d bytes). " | ||
1467 | "Truncating results to %zd bytes.\n", | ||
1468 | dev->name, len, sizeof(*bss)); | ||
1469 | len = sizeof(*bss); | ||
1470 | } else if (len < (offsetof(struct agere_ext_scan_info, | ||
1471 | data) + 2)) { | 1527 | data) + 2)) { |
1472 | /* Drop this result now so we don't have to | 1528 | /* Drop this result now so we don't have to |
1473 | * keep checking later */ | 1529 | * keep checking later */ |
@@ -1477,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1477 | break; | 1533 | break; |
1478 | } | 1534 | } |
1479 | 1535 | ||
1480 | bss = kmalloc(sizeof(*bss), GFP_ATOMIC); | 1536 | bss = kmalloc(len, GFP_ATOMIC); |
1481 | if (bss == NULL) | 1537 | if (bss == NULL) |
1482 | break; | 1538 | break; |
1483 | 1539 | ||
1484 | /* Read scan data */ | 1540 | /* Read scan data */ |
1485 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, | 1541 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, |
1486 | infofid, sizeof(info)); | 1542 | infofid, sizeof(info)); |
1487 | if (err) { | 1543 | if (err) |
1488 | kfree(bss); | 1544 | kfree(bss); |
1489 | break; | 1545 | else |
1490 | } | 1546 | qbuf_scan(priv, bss, len, type); |
1491 | |||
1492 | orinoco_add_ext_scan_result(priv, bss); | ||
1493 | 1547 | ||
1494 | kfree(bss); | ||
1495 | break; | 1548 | break; |
1496 | } | 1549 | } |
1497 | case HERMES_INQ_SEC_STAT_AGERE: | 1550 | case HERMES_INQ_SEC_STAT_AGERE: |
@@ -1506,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1506 | /* We don't actually do anything about it */ | 1559 | /* We don't actually do anything about it */ |
1507 | break; | 1560 | break; |
1508 | } | 1561 | } |
1562 | |||
1563 | return; | ||
1509 | } | 1564 | } |
1510 | 1565 | ||
1511 | static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) | 1566 | static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) |
@@ -1649,9 +1704,11 @@ void orinoco_reset(struct work_struct *work) | |||
1649 | 1704 | ||
1650 | orinoco_unlock(priv, &flags); | 1705 | orinoco_unlock(priv, &flags); |
1651 | 1706 | ||
1652 | /* Scanning support: Cleanup of driver struct */ | 1707 | /* Scanning support: Notify scan cancellation */ |
1653 | orinoco_clear_scan_results(priv, 0); | 1708 | if (priv->scan_request) { |
1654 | priv->scan_inprogress = 0; | 1709 | cfg80211_scan_done(priv->scan_request, 1); |
1710 | priv->scan_request = NULL; | ||
1711 | } | ||
1655 | 1712 | ||
1656 | if (priv->hard_reset) { | 1713 | if (priv->hard_reset) { |
1657 | err = (*priv->hard_reset)(priv); | 1714 | err = (*priv->hard_reset)(priv); |
@@ -1965,12 +2022,6 @@ int orinoco_init(struct orinoco_private *priv) | |||
1965 | } | 2022 | } |
1966 | } | 2023 | } |
1967 | 2024 | ||
1968 | /* Now we have the firmware capabilities, allocate appropiate | ||
1969 | * sized scan buffers */ | ||
1970 | if (orinoco_bss_data_allocate(priv)) | ||
1971 | goto out; | ||
1972 | orinoco_bss_data_init(priv); | ||
1973 | |||
1974 | err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); | 2025 | err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); |
1975 | if (err) | 2026 | if (err) |
1976 | goto out; | 2027 | goto out; |
@@ -2100,6 +2151,10 @@ struct orinoco_private | |||
2100 | tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, | 2151 | tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, |
2101 | (unsigned long) priv); | 2152 | (unsigned long) priv); |
2102 | 2153 | ||
2154 | spin_lock_init(&priv->scan_lock); | ||
2155 | INIT_LIST_HEAD(&priv->scan_list); | ||
2156 | INIT_WORK(&priv->process_scan, orinoco_process_scan_results); | ||
2157 | |||
2103 | priv->last_linkstatus = 0xffff; | 2158 | priv->last_linkstatus = 0xffff; |
2104 | 2159 | ||
2105 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) | 2160 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) |
@@ -2192,6 +2247,7 @@ void free_orinocodev(struct orinoco_private *priv) | |||
2192 | { | 2247 | { |
2193 | struct wiphy *wiphy = priv_to_wiphy(priv); | 2248 | struct wiphy *wiphy = priv_to_wiphy(priv); |
2194 | struct orinoco_rx_data *rx_data, *temp; | 2249 | struct orinoco_rx_data *rx_data, *temp; |
2250 | struct orinoco_scan_data *sd, *sdtemp; | ||
2195 | 2251 | ||
2196 | wiphy_unregister(wiphy); | 2252 | wiphy_unregister(wiphy); |
2197 | 2253 | ||
@@ -2209,13 +2265,22 @@ void free_orinocodev(struct orinoco_private *priv) | |||
2209 | kfree(rx_data); | 2265 | kfree(rx_data); |
2210 | } | 2266 | } |
2211 | 2267 | ||
2268 | cancel_work_sync(&priv->process_scan); | ||
2269 | /* Explicitly drain priv->scan_list */ | ||
2270 | list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { | ||
2271 | list_del(&sd->list); | ||
2272 | |||
2273 | if ((sd->len > 0) && sd->buf) | ||
2274 | kfree(sd->buf); | ||
2275 | kfree(sd); | ||
2276 | } | ||
2277 | |||
2212 | orinoco_unregister_pm_notifier(priv); | 2278 | orinoco_unregister_pm_notifier(priv); |
2213 | orinoco_uncache_fw(priv); | 2279 | orinoco_uncache_fw(priv); |
2214 | 2280 | ||
2215 | priv->wpa_ie_len = 0; | 2281 | priv->wpa_ie_len = 0; |
2216 | kfree(priv->wpa_ie); | 2282 | kfree(priv->wpa_ie); |
2217 | orinoco_mic_free(priv); | 2283 | orinoco_mic_free(priv); |
2218 | orinoco_bss_data_free(priv); | ||
2219 | wiphy_free(wiphy); | 2284 | wiphy_free(wiphy); |
2220 | } | 2285 | } |
2221 | EXPORT_SYMBOL(free_orinocodev); | 2286 | EXPORT_SYMBOL(free_orinocodev); |