Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
0003  * Copyright (c) 2004-2005 Atheros Communications, Inc.
0004  * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
0005  * Copyright (c) 2009 Bob Copeland <me@bobcopeland.com>
0006  *
0007  * All rights reserved.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer,
0014  *    without modification.
0015  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
0016  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
0017  *    redistribution must be conditioned upon including a substantially
0018  *    similar Disclaimer requirement for further binary redistribution.
0019  * 3. Neither the names of the above-listed copyright holders nor the names
0020  *    of any contributors may be used to endorse or promote products derived
0021  *    from this software without specific prior written permission.
0022  *
0023  * Alternatively, this software may be distributed under the terms of the
0024  * GNU General Public License ("GPL") version 2 as published by the Free
0025  * Software Foundation.
0026  *
0027  * NO WARRANTY
0028  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0029  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0030  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
0031  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
0032  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
0033  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0034  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0035  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0036  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0037  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0038  * THE POSSIBILITY OF SUCH DAMAGES.
0039  *
0040  */
0041 
0042 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0043 
0044 #include <linux/pci.h>
0045 #include "ath5k.h"
0046 
0047 #define ATH_SDEVICE(subv, subd) \
0048     .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
0049     .subvendor = (subv), .subdevice = (subd)
0050 
0051 #define ATH_LED(pin, polarity) .driver_data = (((pin) << 8) | (polarity))
0052 #define ATH_PIN(data) ((data) >> 8)
0053 #define ATH_POLARITY(data) ((data) & 0xff)
0054 
0055 /* Devices we match on for LED config info (typically laptops) */
0056 static const struct pci_device_id ath5k_led_devices[] = {
0057     /* AR5211 */
0058     { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) },
0059     /* HP Compaq nc6xx, nc4000, nx6000 */
0060     { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) },
0061     /* Acer Aspire One A150 (maximlevitsky@gmail.com) */
0062     { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) },
0063     /* Acer Aspire One AO531h AO751h (keng-yu.lin@canonical.com) */
0064     { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe00d), ATH_LED(3, 0) },
0065     /* Acer Ferrari 5000 (russ.dill@gmail.com) */
0066     { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) },
0067     /* E-machines E510 (tuliom@gmail.com) */
0068     { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) },
0069     /* BenQ Joybook R55v (nowymarluk@wp.pl) */
0070     { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0100), ATH_LED(1, 0) },
0071     /* Acer Extensa 5620z (nekoreeve@gmail.com) */
0072     { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) },
0073     /* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */
0074     { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
0075     /* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */
0076     { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) },
0077     /* HP Compaq CQ60-206US (ddreggors@jumptv.com) */
0078     { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
0079     /* HP Compaq C700 (nitrousnrg@gmail.com) */
0080     { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 0) },
0081     /* LiteOn AR5BXB63 (magooz@salug.it) */
0082     { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
0083     /* IBM-specific AR5212 (all others) */
0084     { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
0085     /* Dell Vostro A860 (shahar@shahar-or.co.il) */
0086     { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0112), ATH_LED(3, 0) },
0087     { }
0088 };
0089 
0090 void ath5k_led_enable(struct ath5k_hw *ah)
0091 {
0092     if (IS_ENABLED(CONFIG_MAC80211_LEDS) &&
0093         test_bit(ATH_STAT_LEDSOFT, ah->status)) {
0094         ath5k_hw_set_gpio_output(ah, ah->led_pin);
0095         ath5k_led_off(ah);
0096     }
0097 }
0098 
0099 static void ath5k_led_on(struct ath5k_hw *ah)
0100 {
0101     if (!test_bit(ATH_STAT_LEDSOFT, ah->status))
0102         return;
0103     ath5k_hw_set_gpio(ah, ah->led_pin, ah->led_on);
0104 }
0105 
0106 void ath5k_led_off(struct ath5k_hw *ah)
0107 {
0108     if (!IS_ENABLED(CONFIG_MAC80211_LEDS) ||
0109         !test_bit(ATH_STAT_LEDSOFT, ah->status))
0110         return;
0111     ath5k_hw_set_gpio(ah, ah->led_pin, !ah->led_on);
0112 }
0113 
0114 static void
0115 ath5k_led_brightness_set(struct led_classdev *led_dev,
0116     enum led_brightness brightness)
0117 {
0118     struct ath5k_led *led = container_of(led_dev, struct ath5k_led,
0119         led_dev);
0120 
0121     if (brightness == LED_OFF)
0122         ath5k_led_off(led->ah);
0123     else
0124         ath5k_led_on(led->ah);
0125 }
0126 
0127 static int
0128 ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
0129            const char *name, const char *trigger)
0130 {
0131     int err;
0132 
0133     led->ah = ah;
0134     strncpy(led->name, name, sizeof(led->name));
0135     led->name[sizeof(led->name)-1] = 0;
0136     led->led_dev.name = led->name;
0137     led->led_dev.default_trigger = trigger;
0138     led->led_dev.brightness_set = ath5k_led_brightness_set;
0139 
0140     err = led_classdev_register(ah->dev, &led->led_dev);
0141     if (err) {
0142         ATH5K_WARN(ah, "could not register LED %s\n", name);
0143         led->ah = NULL;
0144     }
0145     return err;
0146 }
0147 
0148 static void
0149 ath5k_unregister_led(struct ath5k_led *led)
0150 {
0151     if (!IS_ENABLED(CONFIG_MAC80211_LEDS) || !led->ah)
0152         return;
0153     led_classdev_unregister(&led->led_dev);
0154     ath5k_led_off(led->ah);
0155     led->ah = NULL;
0156 }
0157 
0158 void ath5k_unregister_leds(struct ath5k_hw *ah)
0159 {
0160     ath5k_unregister_led(&ah->rx_led);
0161     ath5k_unregister_led(&ah->tx_led);
0162 }
0163 
0164 int ath5k_init_leds(struct ath5k_hw *ah)
0165 {
0166     int ret = 0;
0167     struct ieee80211_hw *hw = ah->hw;
0168 #ifndef CONFIG_ATH5K_AHB
0169     struct pci_dev *pdev = ah->pdev;
0170 #endif
0171     char name[ATH5K_LED_MAX_NAME_LEN + 1];
0172     const struct pci_device_id *match;
0173 
0174     if (!IS_ENABLED(CONFIG_MAC80211_LEDS) || !ah->pdev)
0175         return 0;
0176 
0177 #ifdef CONFIG_ATH5K_AHB
0178     match = NULL;
0179 #else
0180     match = pci_match_id(&ath5k_led_devices[0], pdev);
0181 #endif
0182     if (match) {
0183         __set_bit(ATH_STAT_LEDSOFT, ah->status);
0184         ah->led_pin = ATH_PIN(match->driver_data);
0185         ah->led_on = ATH_POLARITY(match->driver_data);
0186     }
0187 
0188     if (!test_bit(ATH_STAT_LEDSOFT, ah->status))
0189         goto out;
0190 
0191     ath5k_led_enable(ah);
0192 
0193     snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
0194     ret = ath5k_register_led(ah, &ah->rx_led, name,
0195         ieee80211_get_rx_led_name(hw));
0196     if (ret)
0197         goto out;
0198 
0199     snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
0200     ret = ath5k_register_led(ah, &ah->tx_led, name,
0201         ieee80211_get_tx_led_name(hw));
0202 out:
0203     return ret;
0204 }
0205