diff options
author | Vasanthakumar Thiagarajan <vasanth@atheros.com> | 2008-08-25 11:17:29 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-29 16:24:09 -0400 |
commit | c83be6885e2f1ee6e0b290b6cfc82014c675e087 (patch) | |
tree | ee8410596f5400b916e391b861b4537014355ebb /drivers | |
parent | 36aedc903ea11a4188de0a118d26c9f20afdd272 (diff) |
ath9k: Add LED support
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/core.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/hw.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 138 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/reg.h | 6 |
5 files changed, 176 insertions, 46 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 841893b0b4d4..020b97fd208c 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -757,14 +757,11 @@ struct ath9k_node_stats { | |||
757 | 757 | ||
758 | #define ATH9K_RSSI_EP_MULTIPLIER (1<<7) | 758 | #define ATH9K_RSSI_EP_MULTIPLIER (1<<7) |
759 | 759 | ||
760 | enum ath9k_gpio_output_mux_type { | 760 | #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 |
761 | ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT, | 761 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 |
762 | ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, | 762 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 |
763 | ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, | 763 | #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 |
764 | ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, | 764 | #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 |
765 | ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, | ||
766 | ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES | ||
767 | }; | ||
768 | 765 | ||
769 | enum { | 766 | enum { |
770 | ATH9K_RESET_POWER_ON, | 767 | ATH9K_RESET_POWER_ON, |
@@ -1008,4 +1005,7 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah, | |||
1008 | bool ath9k_get_channel_edges(struct ath_hal *ah, | 1005 | bool ath9k_get_channel_edges(struct ath_hal *ah, |
1009 | u16 flags, u16 *low, | 1006 | u16 flags, u16 *low, |
1010 | u16 *high); | 1007 | u16 *high); |
1008 | void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, | ||
1009 | u32 ah_signal_type); | ||
1010 | void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); | ||
1011 | #endif | 1011 | #endif |
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index de1d12f7c64a..0692fc340268 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/scatterlist.h> | 39 | #include <linux/scatterlist.h> |
40 | #include <asm/page.h> | 40 | #include <asm/page.h> |
41 | #include <net/mac80211.h> | 41 | #include <net/mac80211.h> |
42 | #include <linux/leds.h> | ||
42 | 43 | ||
43 | #include "ath9k.h" | 44 | #include "ath9k.h" |
44 | #include "rc.h" | 45 | #include "rc.h" |
@@ -803,6 +804,27 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv, | |||
803 | void ath_setdefantenna(void *sc, u32 antenna); | 804 | void ath_setdefantenna(void *sc, u32 antenna); |
804 | 805 | ||
805 | /********************/ | 806 | /********************/ |
807 | /* LED Control */ | ||
808 | /********************/ | ||
809 | |||
810 | #define ATH_LED_PIN 1 | ||
811 | |||
812 | enum ath_led_type { | ||
813 | ATH_LED_RADIO, | ||
814 | ATH_LED_ASSOC, | ||
815 | ATH_LED_TX, | ||
816 | ATH_LED_RX | ||
817 | }; | ||
818 | |||
819 | struct ath_led { | ||
820 | struct ath_softc *sc; | ||
821 | struct led_classdev led_cdev; | ||
822 | enum ath_led_type led_type; | ||
823 | char name[32]; | ||
824 | bool registered; | ||
825 | }; | ||
826 | |||
827 | /********************/ | ||
806 | /* Main driver core */ | 828 | /* Main driver core */ |
807 | /********************/ | 829 | /********************/ |
808 | 830 | ||
@@ -884,6 +906,7 @@ struct ath_ht_info { | |||
884 | #define SC_OP_PREAMBLE_SHORT BIT(7) | 906 | #define SC_OP_PREAMBLE_SHORT BIT(7) |
885 | #define SC_OP_PROTECT_ENABLE BIT(8) | 907 | #define SC_OP_PROTECT_ENABLE BIT(8) |
886 | #define SC_OP_RXFLUSH BIT(9) | 908 | #define SC_OP_RXFLUSH BIT(9) |
909 | #define SC_OP_LED_ASSOCIATED BIT(10) | ||
887 | 910 | ||
888 | struct ath_softc { | 911 | struct ath_softc { |
889 | struct ieee80211_hw *hw; | 912 | struct ieee80211_hw *hw; |
@@ -988,6 +1011,12 @@ struct ath_softc { | |||
988 | spinlock_t sc_txbuflock; | 1011 | spinlock_t sc_txbuflock; |
989 | spinlock_t sc_resetlock; | 1012 | spinlock_t sc_resetlock; |
990 | spinlock_t node_lock; | 1013 | spinlock_t node_lock; |
1014 | |||
1015 | /* LEDs */ | ||
1016 | struct ath_led radio_led; | ||
1017 | struct ath_led assoc_led; | ||
1018 | struct ath_led tx_led; | ||
1019 | struct ath_led rx_led; | ||
991 | }; | 1020 | }; |
992 | 1021 | ||
993 | int ath_init(u16 devid, struct ath_softc *sc); | 1022 | int ath_init(u16 devid, struct ath_softc *sc); |
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 47c60acac41f..2578411c6019 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c | |||
@@ -2800,32 +2800,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, | |||
2800 | } | 2800 | } |
2801 | } | 2801 | } |
2802 | 2802 | ||
2803 | static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, | 2803 | void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, |
2804 | enum ath9k_gpio_output_mux_type | 2804 | u32 ah_signal_type) |
2805 | halSignalType) | ||
2806 | { | 2805 | { |
2807 | u32 ah_signal_type; | ||
2808 | u32 gpio_shift; | 2806 | u32 gpio_shift; |
2809 | 2807 | ||
2810 | static u32 MuxSignalConversionTable[] = { | ||
2811 | |||
2812 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT, | ||
2813 | |||
2814 | AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, | ||
2815 | |||
2816 | AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, | ||
2817 | |||
2818 | AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, | ||
2819 | |||
2820 | AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, | ||
2821 | }; | ||
2822 | |||
2823 | if ((halSignalType >= 0) | ||
2824 | && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable))) | ||
2825 | ah_signal_type = MuxSignalConversionTable[halSignalType]; | ||
2826 | else | ||
2827 | return false; | ||
2828 | |||
2829 | ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); | 2808 | ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); |
2830 | 2809 | ||
2831 | gpio_shift = 2 * gpio; | 2810 | gpio_shift = 2 * gpio; |
@@ -2834,16 +2813,12 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, | |||
2834 | AR_GPIO_OE_OUT, | 2813 | AR_GPIO_OE_OUT, |
2835 | (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), | 2814 | (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), |
2836 | (AR_GPIO_OE_OUT_DRV << gpio_shift)); | 2815 | (AR_GPIO_OE_OUT_DRV << gpio_shift)); |
2837 | |||
2838 | return true; | ||
2839 | } | 2816 | } |
2840 | 2817 | ||
2841 | static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, | 2818 | void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) |
2842 | u32 val) | ||
2843 | { | 2819 | { |
2844 | REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), | 2820 | REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), |
2845 | AR_GPIO_BIT(gpio)); | 2821 | AR_GPIO_BIT(gpio)); |
2846 | return true; | ||
2847 | } | 2822 | } |
2848 | 2823 | ||
2849 | static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) | 2824 | static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) |
@@ -5923,7 +5898,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, | |||
5923 | else | 5898 | else |
5924 | ath9k_hw_set_gpio(ah, 9, 1); | 5899 | ath9k_hw_set_gpio(ah, 9, 1); |
5925 | } | 5900 | } |
5926 | ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT); | 5901 | ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
5927 | } | 5902 | } |
5928 | 5903 | ||
5929 | ecode = ath9k_hw_process_ini(ah, chan, macmode); | 5904 | ecode = ath9k_hw_process_ini(ah, chan, macmode); |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dca00c3a985a..996bb9c6540d 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -1172,12 +1172,130 @@ enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) | |||
1172 | return sc->sc_ht_info.tx_chan_width; | 1172 | return sc->sc_ht_info.tx_chan_width; |
1173 | } | 1173 | } |
1174 | 1174 | ||
1175 | /********************************/ | ||
1176 | /* LED functions */ | ||
1177 | /********************************/ | ||
1178 | |||
1179 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
1180 | enum led_brightness brightness) | ||
1181 | { | ||
1182 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
1183 | struct ath_softc *sc = led->sc; | ||
1184 | |||
1185 | switch (brightness) { | ||
1186 | case LED_OFF: | ||
1187 | if (led->led_type == ATH_LED_ASSOC || | ||
1188 | led->led_type == ATH_LED_RADIO) | ||
1189 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1190 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | ||
1191 | (led->led_type == ATH_LED_RADIO) ? 1 : | ||
1192 | !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); | ||
1193 | break; | ||
1194 | case LED_FULL: | ||
1195 | if (led->led_type == ATH_LED_ASSOC) | ||
1196 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
1197 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | ||
1198 | break; | ||
1199 | default: | ||
1200 | break; | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
1205 | char *trigger) | ||
1206 | { | ||
1207 | int ret; | ||
1208 | |||
1209 | led->sc = sc; | ||
1210 | led->led_cdev.name = led->name; | ||
1211 | led->led_cdev.default_trigger = trigger; | ||
1212 | led->led_cdev.brightness_set = ath_led_brightness; | ||
1213 | |||
1214 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
1215 | if (ret) | ||
1216 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1217 | "Failed to register led:%s", led->name); | ||
1218 | else | ||
1219 | led->registered = 1; | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | static void ath_unregister_led(struct ath_led *led) | ||
1224 | { | ||
1225 | if (led->registered) { | ||
1226 | led_classdev_unregister(&led->led_cdev); | ||
1227 | led->registered = 0; | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | static void ath_deinit_leds(struct ath_softc *sc) | ||
1232 | { | ||
1233 | ath_unregister_led(&sc->assoc_led); | ||
1234 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1235 | ath_unregister_led(&sc->tx_led); | ||
1236 | ath_unregister_led(&sc->rx_led); | ||
1237 | ath_unregister_led(&sc->radio_led); | ||
1238 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1239 | } | ||
1240 | |||
1241 | static void ath_init_leds(struct ath_softc *sc) | ||
1242 | { | ||
1243 | char *trigger; | ||
1244 | int ret; | ||
1245 | |||
1246 | /* Configure gpio 1 for output */ | ||
1247 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
1248 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1249 | /* LED off, active low */ | ||
1250 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1251 | |||
1252 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
1253 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
1254 | "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); | ||
1255 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
1256 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
1257 | if (ret) | ||
1258 | goto fail; | ||
1259 | |||
1260 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
1261 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
1262 | "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); | ||
1263 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
1264 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
1265 | if (ret) | ||
1266 | goto fail; | ||
1267 | |||
1268 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
1269 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
1270 | "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); | ||
1271 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
1272 | sc->tx_led.led_type = ATH_LED_TX; | ||
1273 | if (ret) | ||
1274 | goto fail; | ||
1275 | |||
1276 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
1277 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
1278 | "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); | ||
1279 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
1280 | sc->rx_led.led_type = ATH_LED_RX; | ||
1281 | if (ret) | ||
1282 | goto fail; | ||
1283 | |||
1284 | return; | ||
1285 | |||
1286 | fail: | ||
1287 | ath_deinit_leds(sc); | ||
1288 | } | ||
1289 | |||
1175 | static int ath_detach(struct ath_softc *sc) | 1290 | static int ath_detach(struct ath_softc *sc) |
1176 | { | 1291 | { |
1177 | struct ieee80211_hw *hw = sc->hw; | 1292 | struct ieee80211_hw *hw = sc->hw; |
1178 | 1293 | ||
1179 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); | 1294 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); |
1180 | 1295 | ||
1296 | /* Deinit LED control */ | ||
1297 | ath_deinit_leds(sc); | ||
1298 | |||
1181 | /* Unregister hw */ | 1299 | /* Unregister hw */ |
1182 | 1300 | ||
1183 | ieee80211_unregister_hw(hw); | 1301 | ieee80211_unregister_hw(hw); |
@@ -1271,18 +1389,21 @@ static int ath_attach(u16 devid, | |||
1271 | goto bad; | 1389 | goto bad; |
1272 | } | 1390 | } |
1273 | 1391 | ||
1392 | /* Initialize LED control */ | ||
1393 | ath_init_leds(sc); | ||
1394 | |||
1274 | /* initialize tx/rx engine */ | 1395 | /* initialize tx/rx engine */ |
1275 | 1396 | ||
1276 | error = ath_tx_init(sc, ATH_TXBUF); | 1397 | error = ath_tx_init(sc, ATH_TXBUF); |
1277 | if (error != 0) | 1398 | if (error != 0) |
1278 | goto bad1; | 1399 | goto detach; |
1279 | 1400 | ||
1280 | error = ath_rx_init(sc, ATH_RXBUF); | 1401 | error = ath_rx_init(sc, ATH_RXBUF); |
1281 | if (error != 0) | 1402 | if (error != 0) |
1282 | goto bad1; | 1403 | goto detach; |
1283 | 1404 | ||
1284 | return 0; | 1405 | return 0; |
1285 | bad1: | 1406 | detach: |
1286 | ath_detach(sc); | 1407 | ath_detach(sc); |
1287 | bad: | 1408 | bad: |
1288 | return error; | 1409 | return error; |
@@ -1427,6 +1548,10 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
1427 | 1548 | ||
1428 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 1549 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
1429 | { | 1550 | { |
1551 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
1552 | struct ath_softc *sc = hw->priv; | ||
1553 | |||
1554 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1430 | pci_save_state(pdev); | 1555 | pci_save_state(pdev); |
1431 | pci_disable_device(pdev); | 1556 | pci_disable_device(pdev); |
1432 | pci_set_power_state(pdev, 3); | 1557 | pci_set_power_state(pdev, 3); |
@@ -1436,6 +1561,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1436 | 1561 | ||
1437 | static int ath_pci_resume(struct pci_dev *pdev) | 1562 | static int ath_pci_resume(struct pci_dev *pdev) |
1438 | { | 1563 | { |
1564 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
1565 | struct ath_softc *sc = hw->priv; | ||
1439 | u32 val; | 1566 | u32 val; |
1440 | int err; | 1567 | int err; |
1441 | 1568 | ||
@@ -1452,6 +1579,11 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
1452 | if ((val & 0x0000ff00) != 0) | 1579 | if ((val & 0x0000ff00) != 0) |
1453 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | 1580 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); |
1454 | 1581 | ||
1582 | /* Enable LED */ | ||
1583 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
1584 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1585 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
1586 | |||
1455 | return 0; | 1587 | return 0; |
1456 | } | 1588 | } |
1457 | 1589 | ||
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 42b0890a4685..60617ae66209 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h | |||
@@ -899,12 +899,6 @@ enum { | |||
899 | #define AR_GPIO_OUTPUT_MUX2 0x4064 | 899 | #define AR_GPIO_OUTPUT_MUX2 0x4064 |
900 | #define AR_GPIO_OUTPUT_MUX3 0x4068 | 900 | #define AR_GPIO_OUTPUT_MUX3 0x4068 |
901 | 901 | ||
902 | #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 | ||
903 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 | ||
904 | #define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 | ||
905 | #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 | ||
906 | #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 | ||
907 | |||
908 | #define AR_INPUT_STATE 0x406c | 902 | #define AR_INPUT_STATE 0x406c |
909 | 903 | ||
910 | #define AR_EEPROM_STATUS_DATA 0x407c | 904 | #define AR_EEPROM_STATUS_DATA 0x407c |