162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
362306a36Sopenharmony_ci * Copyright (c) 2006 Sam Leffler, Errno Consulting
462306a36Sopenharmony_ci * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
562306a36Sopenharmony_ci * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
662306a36Sopenharmony_ci * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
962306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
1062306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1362306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1462306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1562306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1662306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1762306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1862306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define AR5523_FLAG_PRE_FIRMWARE	(1 << 0)
2262306a36Sopenharmony_ci#define AR5523_FLAG_ABG			(1 << 1)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define AR5523_FIRMWARE_FILE	"ar5523.bin"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define AR5523_CMD_TX_PIPE	0x01
2762306a36Sopenharmony_ci#define	AR5523_DATA_TX_PIPE	0x02
2862306a36Sopenharmony_ci#define	AR5523_CMD_RX_PIPE	0x81
2962306a36Sopenharmony_ci#define	AR5523_DATA_RX_PIPE	0x82
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define ar5523_cmd_tx_pipe(dev) \
3262306a36Sopenharmony_ci	usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE)
3362306a36Sopenharmony_ci#define ar5523_data_tx_pipe(dev) \
3462306a36Sopenharmony_ci	usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE)
3562306a36Sopenharmony_ci#define ar5523_cmd_rx_pipe(dev) \
3662306a36Sopenharmony_ci	usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE)
3762306a36Sopenharmony_ci#define ar5523_data_rx_pipe(dev) \
3862306a36Sopenharmony_ci	usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define	AR5523_DATA_TIMEOUT	10000
4162306a36Sopenharmony_ci#define	AR5523_CMD_TIMEOUT	1000
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define AR5523_TX_DATA_COUNT		8
4462306a36Sopenharmony_ci#define AR5523_TX_DATA_RESTART_COUNT	2
4562306a36Sopenharmony_ci#define AR5523_RX_DATA_COUNT		16
4662306a36Sopenharmony_ci#define AR5523_RX_DATA_REFILL_COUNT	8
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define AR5523_CMD_ID	1
4962306a36Sopenharmony_ci#define AR5523_DATA_ID	2
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define AR5523_TX_WD_TIMEOUT	(HZ * 2)
5262306a36Sopenharmony_ci#define AR5523_FLUSH_TIMEOUT	(HZ * 3)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cienum AR5523_flags {
5562306a36Sopenharmony_ci	AR5523_HW_UP,
5662306a36Sopenharmony_ci	AR5523_USB_DISCONNECTED,
5762306a36Sopenharmony_ci	AR5523_CONNECTED
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct ar5523_tx_cmd {
6162306a36Sopenharmony_ci	struct ar5523		*ar;
6262306a36Sopenharmony_ci	struct urb		*urb_tx;
6362306a36Sopenharmony_ci	void			*buf_tx;
6462306a36Sopenharmony_ci	void			*odata;
6562306a36Sopenharmony_ci	int			olen;
6662306a36Sopenharmony_ci	int			flags;
6762306a36Sopenharmony_ci	int			res;
6862306a36Sopenharmony_ci	struct completion	done;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* This struct is placed in tx_info->driver_data. It must not be larger
7262306a36Sopenharmony_ci *  than IEEE80211_TX_INFO_DRIVER_DATA_SIZE.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistruct ar5523_tx_data {
7562306a36Sopenharmony_ci	struct list_head	list;
7662306a36Sopenharmony_ci	struct ar5523		*ar;
7762306a36Sopenharmony_ci	struct urb		*urb;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct ar5523_rx_data {
8162306a36Sopenharmony_ci	struct	list_head	list;
8262306a36Sopenharmony_ci	struct ar5523		*ar;
8362306a36Sopenharmony_ci	struct urb		*urb;
8462306a36Sopenharmony_ci	struct sk_buff		*skb;
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct ar5523 {
8862306a36Sopenharmony_ci	struct usb_device	*dev;
8962306a36Sopenharmony_ci	struct ieee80211_hw	*hw;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	unsigned long		flags;
9262306a36Sopenharmony_ci	struct mutex		mutex;
9362306a36Sopenharmony_ci	struct workqueue_struct *wq;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	struct ar5523_tx_cmd	tx_cmd;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	struct delayed_work	stat_work;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	struct timer_list	tx_wd_timer;
10062306a36Sopenharmony_ci	struct work_struct	tx_wd_work;
10162306a36Sopenharmony_ci	struct work_struct	tx_work;
10262306a36Sopenharmony_ci	struct list_head	tx_queue_pending;
10362306a36Sopenharmony_ci	struct list_head	tx_queue_submitted;
10462306a36Sopenharmony_ci	spinlock_t		tx_data_list_lock;
10562306a36Sopenharmony_ci	wait_queue_head_t	tx_flush_waitq;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Queued + Submitted TX frames */
10862306a36Sopenharmony_ci	atomic_t		tx_nr_total;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Submitted TX frames */
11162306a36Sopenharmony_ci	atomic_t		tx_nr_pending;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	void			*rx_cmd_buf;
11462306a36Sopenharmony_ci	struct urb		*rx_cmd_urb;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	struct ar5523_rx_data	rx_data[AR5523_RX_DATA_COUNT];
11762306a36Sopenharmony_ci	spinlock_t		rx_data_list_lock;
11862306a36Sopenharmony_ci	struct list_head	rx_data_free;
11962306a36Sopenharmony_ci	struct list_head	rx_data_used;
12062306a36Sopenharmony_ci	atomic_t		rx_data_free_cnt;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	struct work_struct	rx_refill_work;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	unsigned int		rxbufsz;
12562306a36Sopenharmony_ci	u8			serial[16];
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	struct ieee80211_channel channels[14];
12862306a36Sopenharmony_ci	struct ieee80211_rate	rates[12];
12962306a36Sopenharmony_ci	struct ieee80211_supported_band band;
13062306a36Sopenharmony_ci	struct ieee80211_vif	*vif;
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/* flags for sending firmware commands */
13462306a36Sopenharmony_ci#define AR5523_CMD_FLAG_READ	(1 << 1)
13562306a36Sopenharmony_ci#define AR5523_CMD_FLAG_MAGIC	(1 << 2)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define ar5523_dbg(ar, format, arg...) \
13862306a36Sopenharmony_ci	dev_dbg(&(ar)->dev->dev, format, ## arg)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* On USB hot-unplug there can be a lot of URBs in flight and they'll all
14162306a36Sopenharmony_ci * fail. Instead of dealing with them in every possible place just surpress
14262306a36Sopenharmony_ci * any messages on USB disconnect.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ci#define ar5523_err(ar, format, arg...) \
14562306a36Sopenharmony_cido { \
14662306a36Sopenharmony_ci	if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \
14762306a36Sopenharmony_ci		dev_err(&(ar)->dev->dev, format, ## arg); \
14862306a36Sopenharmony_ci	} \
14962306a36Sopenharmony_ci} while (0)
15062306a36Sopenharmony_ci#define ar5523_info(ar, format, arg...)	\
15162306a36Sopenharmony_ci	dev_info(&(ar)->dev->dev, format, ## arg)
152