Linux Kernel
3.7.1
|
#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/completion.h>
#include <linux/rwsem.h>
#include <linux/atomic.h>
#include <net/wimax.h>
#include <linux/wimax/i2400m.h>
#include <asm/byteorder.h>
Go to the source code of this file.
Data Structures | |
struct | i2400m_poke_table |
struct | i2400m |
Macros | |
#define | I2400M_FW_POKE(a, d) |
Enumerations | |
enum | { I2400M_MAX_MTU = 1400 } |
enum | { I2400M_BM_CMD_BUF_SIZE = 16 * 1024, I2400M_BM_ACK_BUF_SIZE = 256 } |
enum | { I2400M_BUS_RESET_RETRIES = 3 } |
enum | i2400m_reset_type { I2400M_RT_WARM, I2400M_RT_COLD, I2400M_RT_BUS } |
enum | i2400m_bm_cmd_flags { I2400M_BM_CMD_RAW = 1 << 2 } |
enum | i2400m_bri { I2400M_BRI_SOFT = 1 << 1, I2400M_BRI_NO_REBOOT = 1 << 2, I2400M_BRI_MAC_REINIT = 1 << 3 } |
Variables | |
struct attribute_group | i2400m_dev_attr_group |
anonymous enum |
enum i2400m_bm_cmd_flags |
enum i2400m_bri |
i2400m_bri - Boot-ROM indicators
Flags for i2400m_bootrom_init() and i2400m_dev_bootstrap() [which are passed from things like i2400m_setup()]. Can be combined with |.
: The device rebooted already and a reboot barker received, proceed directly to ack the boot sequence. : Do not reboot the device and proceed directly to wait for a reboot barker from the device. : We need to reinitialize the boot rom after reading the MAC address. This is quite a dirty hack, if you ask me – the device requires the bootrom to be initialized after reading the MAC address.
enum i2400m_reset_type |
i2400m_reset_type - methods to reset a device
: Reset without device disconnection, device handles are kept valid but state is back to power on, with firmware re-uploaded. : Tell the device to disconnect itself from the bus and reconnect. Renders all device handles invalid. : Tells the bus to reset the device; last measure used when both types above don't work.
void i2400m_bm_cmd_prepare | ( | struct i2400m_bootrom_header * | cmd | ) |
Prepare a boot-mode command for delivery
: pointer to bootrom header to prepare
Computes checksum if so needed. After calling this function, DO NOT modify the command or header as the checksum won't work anymore.
We do it from here because some times we cannot do it in the original context the command was sent (it is a const), so when we copy it to our staging buffer, we add the checksum there.
int i2400m_bootrom_init | ( | struct i2400m * | i2400m, |
enum i2400m_bri | flags | ||
) |
i2400m_bootrom_init - Reboots a powered device into boot mode
: device descriptor : I2400M_BRI_SOFT: a reboot barker has been seen already, so don't wait for it.
I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait for a reboot barker notification. This is a one shot; if the state machine needs to send a reboot command it will.
Returns:
< 0 errno code on error, 0 if ok.
Description:
Tries hard enough to put the device in boot-mode. There are two main phases to this:
a. (1) send a reboot command and (2) get a reboot barker
b. (1) echo/ack the reboot sending the reboot barker back and (2) getting an ack barker in return
We want to skip (a) in some cases [soft]. The state machine is horrible, but it is basically: on each phase, send what has to be sent (if any), wait for the answer and act on the answer. We might have to backtrack and retry, so we keep a max tries counter for that.
It sucks because we don't know ahead of time which is going to be the reboot barker (the device might send different ones depending on its EEPROM config) and once the device reboots and waits for the echo/ack reboot barker being sent back, it doesn't understand anything else. So we can be left at the point where we don't know what to send to it – cold reset and bus reset seem to have little effect. So the function iterates (in this case) through all the known barkers and tries them all until an ACK is received. Otherwise, it gives up.
If we get a timeout after sending a warm reset, we do it again.
int i2400m_dev_bootstrap | ( | struct i2400m * | i2400m, |
enum i2400m_bri | flags | ||
) |
i2400m_dev_bootstrap - Bring the device to a known state and upload firmware
: device descriptor
Returns: >= 0 if ok, < 0 errno code on error.
This sets up the firmware upload environment, loads the firmware file from disk, verifies and then calls the firmware upload process per se.
Can be called either from probe, or after a warm reset. Can not be called from within an interrupt. All the flow in this code is single-threade; all I/Os are synchronous.
i2400m_dev_initialize - Initialize the device once communications are ready
: device descriptor
Returns: 0 if ok, < 0 errno code on error.
Configures the device to work the way we like it.
At the point of this call, the device is registered with the WiMAX and netdev stacks, firmware is uploaded and we can talk to the device normally.
i2400m_dev_reset_handle - Handle a device's reset in a thread context
Schedule a device reset handling out on a thread context, so it is safe to call from atomic context. We can't use the i2400m's queue as we are going to destroy it and reinitialize it as part of the driver bringup/bringup process.
See __i2400m_dev_reset_handle() for details; that takes care of reinitializing the driver to handle the reset, calling into the bus-specific functions ops as needed.
i2400m_dev_shutdown - Shutdown a running device
: device descriptor
Release resources acquired during the running of the device; in theory, should also tell the device to go to sleep, switch off the radio, all that, but at this point, in most cases (driver disconnection, reset handling) we can't even talk to the device.
i2400m_firmware_check - check firmware versions are compatible with the driver
: device descriptor
Returns: 0 if ok, < 0 errno code an error and a message in the kernel log.
Long function, but quite simple; first chunk launches the command and double checks the reply for the right TLV. Then we process the TLV (where the meat is).
Once we process the TLV that gives us the firmware's interface version, we encode it and save it in i2400m->fw_version for future reference.
i2400m_get_device_info - Query the device for detailed device information
: device descriptor
Returns: an skb whose skb->data points to a 'struct i2400m_tlv_detailed_device_info'. When done, kfree_skb() it. The skb is guaranteed to contain the whole TLV data structure.
On error, IS_ERR(skb) is true and ERR_PTR(skb) is the error code.
i2400m_msg_to_dev - Send a control message to the device and get a response
: device descriptor
: an skb *
: pointer to the buffer containing the message to be sent; it has to start with a &struct i2400M_l3l4_hdr and then followed by the payload. Once this function returns, the buffer can be reused.
: buffer size
Returns:
Pointer to skb containing the ack message. You need to check the pointer with IS_ERR(), as it might be an error code. Error codes could happen because:
The returned skb has been allocated with wimax_msg_to_user_alloc(), it contains the response in a netlink attribute and is ready to be passed up to user space with wimax_msg_to_user_send(). To access the payload and its length, use wimax_msg_{data,len}() on the skb.
The skb has to be freed with kfree_skb() once done.
Description:
This function delivers a message/command to the device and waits for an ack to be received. The format is described in linux/wimax/i2400m.h. In summary, a command/get/set is followed by an ack.
This function will not check the ack status, that's left up to the caller. Once done with the ack skb, it has to be kfree_skb()ed.
The i2400m handles only one message at the same time, thus we need the mutex to exclude other players.
We write the message and then wait for an answer to come back. The RX path intercepts control messages and handles them in i2400m_rx_ctl(). Reports (notifications) are (maybe) processed locally and then forwarded (as needed) to user space on the WiMAX stack message pipe. Acks are saved and passed back to us through an skb in i2400m->ack_skb which is ready to be given to generic netlink if need be.
void i2400m_netdev_setup | ( | struct net_device * | net_dev | ) |
i2400m_netdev_setup - Setup setup 's i2400m private data
Called by alloc_netdev()
Definition at line 84 of file op-rfkill.c.
i2400m_release - release the bus-generic driver resources
Sends a disconnect message and undoes any setup done by i2400m_setup()
void i2400m_report_hook_work | ( | struct work_struct * | ) |
void i2400m_report_tlv_rf_switches_status | ( | struct i2400m * | , |
const struct i2400m_tlv_rf_switches_status * | |||
) |
Definition at line 165 of file op-rfkill.c.
i2400m_rx - Receive a buffer of data from the device
: device descriptor : skbuff where the data has been received
Parse in a buffer of data that contains an RX message sent from the device. See the file header for the format. Run all checks on the buffer header, then run over each payload's descriptors, verify their consistency and act on each payload's contents. If everything is successful, update the device's statistics.
Note: You need to set the skb to contain only the length of the received buffer; for that, use skb_trim(skb, RECEIVED_SIZE).
Returns:
0 if ok, < 0 errno on error
If ok, this function owns now the skb and the caller DOESN'T have to run kfree_skb() on it. However, on error, the caller still owns the skb and it is responsible for releasing it.
i2400m_set_idle_timeout - Set the device's idle mode timeout
: i2400m device descriptor
: milliseconds for the timeout to enter idle mode. Between 100 to 300000 (5m); 0 to disable. In increments of 100.
After this of the link being idle (no data being sent or received), the device will negotiate with the basestation entering idle mode for saving power. The connection is maintained, but getting out of it (done in tx.c) will require some negotiation, possible crypto re-handshake and a possible DHCP re-lease.
Only available if fw_version >= 0x00090002.
Returns: 0 if ok, < 0 errno code on error.
int i2400m_setup | ( | struct i2400m * | i2400m, |
enum i2400m_bri | bm_flags | ||
) |
i2400m_setup - bus-generic setup function for the i2400m device
: device descriptor (bus-specific parts have been initialized)
Returns: 0 if ok, < 0 errno code on error.
Sets up basic device comunication infrastructure, boots the ROM to read the MAC address, registers with the WiMAX and network stacks and then brings up the device.
void i2400m_sysfs_release | ( | struct device_driver * | ) |
int i2400m_sysfs_setup | ( | struct device_driver * | ) |
i2400m_tx - send the data in a buffer to the device
: pointer to the buffer to transmit
: buffer size
: type of the payload we are sending.
Returns: 0 if ok, < 0 errno code on error (-ENOSPC, if there is no more room for the message in the queue).
Appends the buffer to the TX FIFO and notifies the bus-specific part of the driver that there is new data ready to transmit. Once this function returns, the buffer has been copied, so it can be reused.
The steps followed to append are explained in detail in the file header.
Whenever we write to a message, we increase msg->size, so it reflects exactly how big the message is. This is needed so that if we concatenate two messages before they can be sent, the code that sends the messages can find the boundaries (and it will replace the size with the real barker before sending).
Note:
Cold and warm reset payloads need to be sent as a single payload, so we handle that.
|
read |
i2400m_tx_msg_get - Get the first TX message in the FIFO to start sending it
: device descriptors : where to place the size of the TX message
Called by the bus-specific driver to get the first TX message at the FIF that is ready for transmission.
It sets the state in to indicate the bus-specific driver is transferring that message (i2400m->tx_msg_size).
Once the transfer is completed, call i2400m_tx_msg_sent().
Notes:
The size of the TX message to be transmitted might be smaller than that of the TX message in the FIFO (in case the header was shorter). Hence, we copy it in @bus_size, for the bus layer to use. We keep the message's size in i2400m->tx_msg_size so that when the bus later is done transferring we know how much to advance the fifo. We collect statistics here as all the data is available and we assume it is going to work [see i2400m_tx_msg_sent()].
i2400m_tx_msg_sent - indicate the transmission of a TX message
: device descriptor
Called by the bus-specific driver when a message has been sent; this pops it from the FIFO; and as there is space, start the queue in case it was stopped.
Should be called even if the message send failed and we are dropping this TX message.
void i2400m_wake_tx_work | ( | struct work_struct * | ) |
struct attribute_group i2400m_dev_attr_group |