Loading Documentation/DocBook/mac80211.tmpl +4 −8 Original line number Diff line number Diff line Loading @@ -145,7 +145,6 @@ usage should require reading the full document. this though and the recommendation to allow only a single interface in STA mode at first! </para> !Finclude/net/mac80211.h ieee80211_if_types !Finclude/net/mac80211.h ieee80211_if_init_conf !Finclude/net/mac80211.h ieee80211_if_conf </chapter> Loading Loading @@ -177,8 +176,7 @@ usage should require reading the full document. <title>functions/definitions</title> !Finclude/net/mac80211.h ieee80211_rx_status !Finclude/net/mac80211.h mac80211_rx_flags !Finclude/net/mac80211.h ieee80211_tx_control !Finclude/net/mac80211.h ieee80211_tx_status_flags !Finclude/net/mac80211.h ieee80211_tx_info !Finclude/net/mac80211.h ieee80211_rx !Finclude/net/mac80211.h ieee80211_rx_irqsafe !Finclude/net/mac80211.h ieee80211_tx_status Loading @@ -189,12 +187,11 @@ usage should require reading the full document. !Finclude/net/mac80211.h ieee80211_ctstoself_duration !Finclude/net/mac80211.h ieee80211_generic_frame_duration !Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb !Finclude/net/mac80211.h ieee80211_get_hdrlen !Finclude/net/mac80211.h ieee80211_hdrlen !Finclude/net/mac80211.h ieee80211_wake_queue !Finclude/net/mac80211.h ieee80211_stop_queue !Finclude/net/mac80211.h ieee80211_start_queues !Finclude/net/mac80211.h ieee80211_stop_queues !Finclude/net/mac80211.h ieee80211_wake_queues !Finclude/net/mac80211.h ieee80211_stop_queues </sect1> </chapter> Loading Loading @@ -230,8 +227,7 @@ usage should require reading the full document. <title>Multiple queues and QoS support</title> <para>TBD</para> !Finclude/net/mac80211.h ieee80211_tx_queue_params !Finclude/net/mac80211.h ieee80211_tx_queue_stats_data !Finclude/net/mac80211.h ieee80211_tx_queue !Finclude/net/mac80211.h ieee80211_tx_queue_stats </chapter> <chapter id="AP"> Loading Documentation/feature-removal-schedule.txt +18 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,24 @@ be removed from this file. --------------------------- What: old static regulatory information and ieee80211_regdom module parameter When: 2.6.29 Why: The old regulatory infrastructure has been replaced with a new one which does not require statically defined regulatory domains. We do not want to keep static regulatory domains in the kernel due to the the dynamic nature of regulatory law and localization. We kept around the old static definitions for the regulatory domains of: * US * JP * EU and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was set. We also kept around the ieee80211_regdom module parameter in case some applications were relying on it. Changing regulatory domains can now be done instead by using nl80211, as is done with iw. Who: Luis R. Rodriguez <lrodriguez@atheros.com> --------------------------- What: dev->power.power_state When: July 2007 Why: Broken design for runtime control over driver power states, confusing Loading Documentation/networking/regulatory.txt 0 → 100644 +194 −0 Original line number Diff line number Diff line Linux wireless regulatory documentation --------------------------------------- This document gives a brief review over how the Linux wireless regulatory infrastructure works. More up to date information can be obtained at the project's web page: http://wireless.kernel.org/en/developers/Regulatory Keeping regulatory domains in userspace --------------------------------------- Due to the dynamic nature of regulatory domains we keep them in userspace and provide a framework for userspace to upload to the kernel one regulatory domain to be used as the central core regulatory domain all wireless devices should adhere to. How to get regulatory domains to the kernel ------------------------------------------- Userspace gets a regulatory domain in the kernel by having a userspace agent build it and send it via nl80211. Only expected regulatory domains will be respected by the kernel. A currently available userspace agent which can accomplish this is CRDA - central regulatory domain agent. Its documented here: http://wireless.kernel.org/en/developers/Regulatory/CRDA Essentially the kernel will send a udev event when it knows it needs a new regulatory domain. A udev rule can be put in place to trigger crda to send the respective regulatory domain for a specific ISO/IEC 3166 alpha2. Below is an example udev rule which can be used: # Example file, should be put in /etc/udev/rules.d/regulatory.rules KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda" The alpha2 is passed as an environment variable under the variable COUNTRY. Who asks for regulatory domains? -------------------------------- * Users Users can use iw: http://wireless.kernel.org/en/users/Documentation/iw An example: # set regulatory domain to "Costa Rica" iw reg set CR This will request the kernel to set the regulatory domain to the specificied alpha2. The kernel in turn will then ask userspace to provide a regulatory domain for the alpha2 specified by the user by sending a uevent. * Wireless subsystems for Country Information elements The kernel will send a uevent to inform userspace a new regulatory domain is required. More on this to be added as its integration is added. * Drivers If drivers determine they need a specific regulatory domain set they can inform the wireless core using regulatory_hint(). They have two options -- they either provide an alpha2 so that crda can provide back a regulatory domain for that country or they can build their own regulatory domain based on internal custom knowledge so the wireless core can respect it. *Most* drivers will rely on the first mechanism of providing a regulatory hint with an alpha2. For these drivers there is an additional check that can be used to ensure compliance based on custom EEPROM regulatory data. This additional check can be used by drivers by registering on its struct wiphy a reg_notifier() callback. This notifier is called when the core's regulatory domain has been changed. The driver can use this to review the changes made and also review who made them (driver, user, country IE) and determine what to allow based on its internal EEPROM data. Devices drivers wishing to be capable of world roaming should use this callback. More on world roaming will be added to this document when its support is enabled. Device drivers who provide their own built regulatory domain do not need a callback as the channels registered by them are the only ones that will be allowed and therefore *additional* cannels cannot be enabled. Example code - drivers hinting an alpha2: ------------------------------------------ This example comes from the zd1211rw device driver. You can start by having a mapping of your device's EEPROM country/regulatory domain value to to a specific alpha2 as follows: static struct zd_reg_alpha2_map reg_alpha2_map[] = { { ZD_REGDOMAIN_FCC, "US" }, { ZD_REGDOMAIN_IC, "CA" }, { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ { ZD_REGDOMAIN_JAPAN, "JP" }, { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, { ZD_REGDOMAIN_SPAIN, "ES" }, { ZD_REGDOMAIN_FRANCE, "FR" }, Then you can define a routine to map your read EEPROM value to an alpha2, as follows: static int zd_reg2alpha2(u8 regdomain, char *alpha2) { unsigned int i; struct zd_reg_alpha2_map *reg_map; for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { reg_map = ®_alpha2_map[i]; if (regdomain == reg_map->reg) { alpha2[0] = reg_map->alpha2[0]; alpha2[1] = reg_map->alpha2[1]; return 0; } } return 1; } Lastly, you can then hint to the core of your discovered alpha2, if a match was found. You need to do this after you have registered your wiphy. You are expected to do this during initialization. r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) regulatory_hint(hw->wiphy, alpha2, NULL); Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should kmalloc() a structure big enough to hold your regulatory domain structure and you should then fill it with your data. Finally you simply call regulatory_hint() with the regulatory domain structure in it. Bellow is a simple example, with a regulatory domain cached using the stack. Your implementation may vary (read EEPROM cache instead, for example). Example cache of some regulatory domain struct ieee80211_regdomain mydriver_jp_regdom = { .n_reg_rules = 3, .alpha2 = "JP", //.alpha2 = "99", /* If I have no alpha2 to map it to */ .reg_rules = { /* IEEE 802.11b/g, channels 1..14 */ REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), /* IEEE 802.11a, channels 34..48 */ REG_RULE(5170-20, 5240+20, 40, 6, 20, NL80211_RRF_PASSIVE_SCAN), /* IEEE 802.11a, channels 52..64 */ REG_RULE(5260-20, 5320+20, 40, 6, 20, NL80211_RRF_NO_IBSS | NL80211_RRF_DFS), } }; Then in some part of your code after your wiphy has been registered: int r; struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules; unsigned int i; size_of_regd = sizeof(struct ieee80211_regdomain) + (num_rules * sizeof(struct ieee80211_reg_rule)); rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) return -ENOMEM; memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); for (i=0; i < num_rules; i++) { memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); } r = regulatory_hint(hw->wiphy, NULL, rd); if (r) { kfree(rd); return r; } Documentation/rfkill.txt +28 −4 Original line number Diff line number Diff line Loading @@ -341,6 +341,8 @@ key that does nothing by itself, as well as any hot key that is type-specific 3.1 Guidelines for wireless device drivers ------------------------------------------ (in this text, rfkill->foo means the foo field of struct rfkill). 1. Each independent transmitter in a wireless device (usually there is only one transmitter per device) should have a SINGLE rfkill class attached to it. Loading @@ -363,10 +365,32 @@ This rule exists because users of the rfkill subsystem expect to get (and set, when possible) the overall transmitter rfkill state, not of a particular rfkill line. 5. During suspend, the rfkill class will attempt to soft-block the radio through a call to rfkill->toggle_radio, and will try to restore its previous state during resume. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio until it is resumed. 5. The wireless device driver MUST NOT leave the transmitter enabled during suspend and hibernation unless: 5.1. The transmitter has to be enabled for some sort of functionality like wake-on-wireless-packet or autonomous packed forwarding in a mesh network, and that functionality is enabled for this suspend/hibernation cycle. AND 5.2. The device was not on a user-requested BLOCKED state before the suspend (i.e. the driver must NOT unblock a device, not even to support wake-on-wireless-packet or remain in the mesh). In other words, there is absolutely no allowed scenario where a driver can automatically take action to unblock a rfkill controller (obviously, this deals with scenarios where soft-blocking or both soft and hard blocking is happening. Scenarios where hardware rfkill lines are the only ones blocking the transmitter are outside of this rule, since the wireless device driver does not control its input hardware rfkill lines in the first place). 6. During resume, rfkill will try to restore its previous state. 7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio until it is resumed. Example of a WLAN wireless driver connected to the rfkill subsystem: -------------------------------------------------------------------- Loading drivers/net/wireless/adm8211.c +11 −11 Original line number Diff line number Diff line Loading @@ -765,11 +765,11 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->soft_rx_crc = 0; switch (priv->mode) { case IEEE80211_IF_TYPE_STA: case NL80211_IFTYPE_STATION: priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; break; case IEEE80211_IF_TYPE_IBSS: case NL80211_IFTYPE_ADHOC: priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; Loading @@ -777,7 +777,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; case IEEE80211_IF_TYPE_MNTR: case NL80211_IFTYPE_MONITOR: priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; break; Loading Loading @@ -1410,11 +1410,11 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; if (priv->mode != IEEE80211_IF_TYPE_MNTR) if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: Loading @@ -1437,7 +1437,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_MNTR; priv->mode = NL80211_IFTYPE_MONITOR; } static int adm8211_init_rings(struct ieee80211_hw *dev) Loading Loading @@ -1556,7 +1556,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); priv->mode = IEEE80211_IF_TYPE_MNTR; priv->mode = NL80211_IFTYPE_MONITOR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); Loading @@ -1571,7 +1571,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_INVALID; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); Loading Loading @@ -1896,7 +1896,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; priv->mode = IEEE80211_IF_TYPE_INVALID; priv->mode = NL80211_IFTYPE_UNSPECIFIED; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { Loading Loading @@ -1986,7 +1986,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; if (priv->mode != IEEE80211_IF_TYPE_INVALID) { if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); adm8211_stop(dev); } Loading @@ -2004,7 +2004,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); if (priv->mode != IEEE80211_IF_TYPE_INVALID) { if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { adm8211_start(dev); ieee80211_wake_queues(dev); } Loading Loading
Documentation/DocBook/mac80211.tmpl +4 −8 Original line number Diff line number Diff line Loading @@ -145,7 +145,6 @@ usage should require reading the full document. this though and the recommendation to allow only a single interface in STA mode at first! </para> !Finclude/net/mac80211.h ieee80211_if_types !Finclude/net/mac80211.h ieee80211_if_init_conf !Finclude/net/mac80211.h ieee80211_if_conf </chapter> Loading Loading @@ -177,8 +176,7 @@ usage should require reading the full document. <title>functions/definitions</title> !Finclude/net/mac80211.h ieee80211_rx_status !Finclude/net/mac80211.h mac80211_rx_flags !Finclude/net/mac80211.h ieee80211_tx_control !Finclude/net/mac80211.h ieee80211_tx_status_flags !Finclude/net/mac80211.h ieee80211_tx_info !Finclude/net/mac80211.h ieee80211_rx !Finclude/net/mac80211.h ieee80211_rx_irqsafe !Finclude/net/mac80211.h ieee80211_tx_status Loading @@ -189,12 +187,11 @@ usage should require reading the full document. !Finclude/net/mac80211.h ieee80211_ctstoself_duration !Finclude/net/mac80211.h ieee80211_generic_frame_duration !Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb !Finclude/net/mac80211.h ieee80211_get_hdrlen !Finclude/net/mac80211.h ieee80211_hdrlen !Finclude/net/mac80211.h ieee80211_wake_queue !Finclude/net/mac80211.h ieee80211_stop_queue !Finclude/net/mac80211.h ieee80211_start_queues !Finclude/net/mac80211.h ieee80211_stop_queues !Finclude/net/mac80211.h ieee80211_wake_queues !Finclude/net/mac80211.h ieee80211_stop_queues </sect1> </chapter> Loading Loading @@ -230,8 +227,7 @@ usage should require reading the full document. <title>Multiple queues and QoS support</title> <para>TBD</para> !Finclude/net/mac80211.h ieee80211_tx_queue_params !Finclude/net/mac80211.h ieee80211_tx_queue_stats_data !Finclude/net/mac80211.h ieee80211_tx_queue !Finclude/net/mac80211.h ieee80211_tx_queue_stats </chapter> <chapter id="AP"> Loading
Documentation/feature-removal-schedule.txt +18 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,24 @@ be removed from this file. --------------------------- What: old static regulatory information and ieee80211_regdom module parameter When: 2.6.29 Why: The old regulatory infrastructure has been replaced with a new one which does not require statically defined regulatory domains. We do not want to keep static regulatory domains in the kernel due to the the dynamic nature of regulatory law and localization. We kept around the old static definitions for the regulatory domains of: * US * JP * EU and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was set. We also kept around the ieee80211_regdom module parameter in case some applications were relying on it. Changing regulatory domains can now be done instead by using nl80211, as is done with iw. Who: Luis R. Rodriguez <lrodriguez@atheros.com> --------------------------- What: dev->power.power_state When: July 2007 Why: Broken design for runtime control over driver power states, confusing Loading
Documentation/networking/regulatory.txt 0 → 100644 +194 −0 Original line number Diff line number Diff line Linux wireless regulatory documentation --------------------------------------- This document gives a brief review over how the Linux wireless regulatory infrastructure works. More up to date information can be obtained at the project's web page: http://wireless.kernel.org/en/developers/Regulatory Keeping regulatory domains in userspace --------------------------------------- Due to the dynamic nature of regulatory domains we keep them in userspace and provide a framework for userspace to upload to the kernel one regulatory domain to be used as the central core regulatory domain all wireless devices should adhere to. How to get regulatory domains to the kernel ------------------------------------------- Userspace gets a regulatory domain in the kernel by having a userspace agent build it and send it via nl80211. Only expected regulatory domains will be respected by the kernel. A currently available userspace agent which can accomplish this is CRDA - central regulatory domain agent. Its documented here: http://wireless.kernel.org/en/developers/Regulatory/CRDA Essentially the kernel will send a udev event when it knows it needs a new regulatory domain. A udev rule can be put in place to trigger crda to send the respective regulatory domain for a specific ISO/IEC 3166 alpha2. Below is an example udev rule which can be used: # Example file, should be put in /etc/udev/rules.d/regulatory.rules KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda" The alpha2 is passed as an environment variable under the variable COUNTRY. Who asks for regulatory domains? -------------------------------- * Users Users can use iw: http://wireless.kernel.org/en/users/Documentation/iw An example: # set regulatory domain to "Costa Rica" iw reg set CR This will request the kernel to set the regulatory domain to the specificied alpha2. The kernel in turn will then ask userspace to provide a regulatory domain for the alpha2 specified by the user by sending a uevent. * Wireless subsystems for Country Information elements The kernel will send a uevent to inform userspace a new regulatory domain is required. More on this to be added as its integration is added. * Drivers If drivers determine they need a specific regulatory domain set they can inform the wireless core using regulatory_hint(). They have two options -- they either provide an alpha2 so that crda can provide back a regulatory domain for that country or they can build their own regulatory domain based on internal custom knowledge so the wireless core can respect it. *Most* drivers will rely on the first mechanism of providing a regulatory hint with an alpha2. For these drivers there is an additional check that can be used to ensure compliance based on custom EEPROM regulatory data. This additional check can be used by drivers by registering on its struct wiphy a reg_notifier() callback. This notifier is called when the core's regulatory domain has been changed. The driver can use this to review the changes made and also review who made them (driver, user, country IE) and determine what to allow based on its internal EEPROM data. Devices drivers wishing to be capable of world roaming should use this callback. More on world roaming will be added to this document when its support is enabled. Device drivers who provide their own built regulatory domain do not need a callback as the channels registered by them are the only ones that will be allowed and therefore *additional* cannels cannot be enabled. Example code - drivers hinting an alpha2: ------------------------------------------ This example comes from the zd1211rw device driver. You can start by having a mapping of your device's EEPROM country/regulatory domain value to to a specific alpha2 as follows: static struct zd_reg_alpha2_map reg_alpha2_map[] = { { ZD_REGDOMAIN_FCC, "US" }, { ZD_REGDOMAIN_IC, "CA" }, { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ { ZD_REGDOMAIN_JAPAN, "JP" }, { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, { ZD_REGDOMAIN_SPAIN, "ES" }, { ZD_REGDOMAIN_FRANCE, "FR" }, Then you can define a routine to map your read EEPROM value to an alpha2, as follows: static int zd_reg2alpha2(u8 regdomain, char *alpha2) { unsigned int i; struct zd_reg_alpha2_map *reg_map; for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { reg_map = ®_alpha2_map[i]; if (regdomain == reg_map->reg) { alpha2[0] = reg_map->alpha2[0]; alpha2[1] = reg_map->alpha2[1]; return 0; } } return 1; } Lastly, you can then hint to the core of your discovered alpha2, if a match was found. You need to do this after you have registered your wiphy. You are expected to do this during initialization. r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) regulatory_hint(hw->wiphy, alpha2, NULL); Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should kmalloc() a structure big enough to hold your regulatory domain structure and you should then fill it with your data. Finally you simply call regulatory_hint() with the regulatory domain structure in it. Bellow is a simple example, with a regulatory domain cached using the stack. Your implementation may vary (read EEPROM cache instead, for example). Example cache of some regulatory domain struct ieee80211_regdomain mydriver_jp_regdom = { .n_reg_rules = 3, .alpha2 = "JP", //.alpha2 = "99", /* If I have no alpha2 to map it to */ .reg_rules = { /* IEEE 802.11b/g, channels 1..14 */ REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), /* IEEE 802.11a, channels 34..48 */ REG_RULE(5170-20, 5240+20, 40, 6, 20, NL80211_RRF_PASSIVE_SCAN), /* IEEE 802.11a, channels 52..64 */ REG_RULE(5260-20, 5320+20, 40, 6, 20, NL80211_RRF_NO_IBSS | NL80211_RRF_DFS), } }; Then in some part of your code after your wiphy has been registered: int r; struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules; unsigned int i; size_of_regd = sizeof(struct ieee80211_regdomain) + (num_rules * sizeof(struct ieee80211_reg_rule)); rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) return -ENOMEM; memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); for (i=0; i < num_rules; i++) { memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); } r = regulatory_hint(hw->wiphy, NULL, rd); if (r) { kfree(rd); return r; }
Documentation/rfkill.txt +28 −4 Original line number Diff line number Diff line Loading @@ -341,6 +341,8 @@ key that does nothing by itself, as well as any hot key that is type-specific 3.1 Guidelines for wireless device drivers ------------------------------------------ (in this text, rfkill->foo means the foo field of struct rfkill). 1. Each independent transmitter in a wireless device (usually there is only one transmitter per device) should have a SINGLE rfkill class attached to it. Loading @@ -363,10 +365,32 @@ This rule exists because users of the rfkill subsystem expect to get (and set, when possible) the overall transmitter rfkill state, not of a particular rfkill line. 5. During suspend, the rfkill class will attempt to soft-block the radio through a call to rfkill->toggle_radio, and will try to restore its previous state during resume. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio until it is resumed. 5. The wireless device driver MUST NOT leave the transmitter enabled during suspend and hibernation unless: 5.1. The transmitter has to be enabled for some sort of functionality like wake-on-wireless-packet or autonomous packed forwarding in a mesh network, and that functionality is enabled for this suspend/hibernation cycle. AND 5.2. The device was not on a user-requested BLOCKED state before the suspend (i.e. the driver must NOT unblock a device, not even to support wake-on-wireless-packet or remain in the mesh). In other words, there is absolutely no allowed scenario where a driver can automatically take action to unblock a rfkill controller (obviously, this deals with scenarios where soft-blocking or both soft and hard blocking is happening. Scenarios where hardware rfkill lines are the only ones blocking the transmitter are outside of this rule, since the wireless device driver does not control its input hardware rfkill lines in the first place). 6. During resume, rfkill will try to restore its previous state. 7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio until it is resumed. Example of a WLAN wireless driver connected to the rfkill subsystem: -------------------------------------------------------------------- Loading
drivers/net/wireless/adm8211.c +11 −11 Original line number Diff line number Diff line Loading @@ -765,11 +765,11 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->soft_rx_crc = 0; switch (priv->mode) { case IEEE80211_IF_TYPE_STA: case NL80211_IFTYPE_STATION: priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; break; case IEEE80211_IF_TYPE_IBSS: case NL80211_IFTYPE_ADHOC: priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; Loading @@ -777,7 +777,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; case IEEE80211_IF_TYPE_MNTR: case NL80211_IFTYPE_MONITOR: priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; break; Loading Loading @@ -1410,11 +1410,11 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; if (priv->mode != IEEE80211_IF_TYPE_MNTR) if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: Loading @@ -1437,7 +1437,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_MNTR; priv->mode = NL80211_IFTYPE_MONITOR; } static int adm8211_init_rings(struct ieee80211_hw *dev) Loading Loading @@ -1556,7 +1556,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); priv->mode = IEEE80211_IF_TYPE_MNTR; priv->mode = NL80211_IFTYPE_MONITOR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); Loading @@ -1571,7 +1571,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_INVALID; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); Loading Loading @@ -1896,7 +1896,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; priv->mode = IEEE80211_IF_TYPE_INVALID; priv->mode = NL80211_IFTYPE_UNSPECIFIED; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { Loading Loading @@ -1986,7 +1986,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; if (priv->mode != IEEE80211_IF_TYPE_INVALID) { if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); adm8211_stop(dev); } Loading @@ -2004,7 +2004,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); if (priv->mode != IEEE80211_IF_TYPE_INVALID) { if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { adm8211_start(dev); ieee80211_wake_queues(dev); } Loading