aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/orinoco/main.c')
-rw-r--r--drivers/net/wireless/orinoco/main.c167
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
209struct 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
1275static 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
1293static 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
1308static 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
1268static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) 1347static 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
1511static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) 1566static 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}
2221EXPORT_SYMBOL(free_orinocodev); 2286EXPORT_SYMBOL(free_orinocodev);