18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
38c2ecf20Sopenharmony_ci * Copyright (c) 2006 Sam Leffler, Errno Consulting
48c2ecf20Sopenharmony_ci * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
58c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
68c2ecf20Sopenharmony_ci * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
98c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
108c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
138c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
148c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
158c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
168c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
178c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
188c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define AR5523_FLAG_PRE_FIRMWARE	(1 << 0)
228c2ecf20Sopenharmony_ci#define AR5523_FLAG_ABG			(1 << 1)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define AR5523_FIRMWARE_FILE	"ar5523.bin"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define AR5523_CMD_TX_PIPE	0x01
278c2ecf20Sopenharmony_ci#define	AR5523_DATA_TX_PIPE	0x02
288c2ecf20Sopenharmony_ci#define	AR5523_CMD_RX_PIPE	0x81
298c2ecf20Sopenharmony_ci#define	AR5523_DATA_RX_PIPE	0x82
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define ar5523_cmd_tx_pipe(dev) \
328c2ecf20Sopenharmony_ci	usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE)
338c2ecf20Sopenharmony_ci#define ar5523_data_tx_pipe(dev) \
348c2ecf20Sopenharmony_ci	usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE)
358c2ecf20Sopenharmony_ci#define ar5523_cmd_rx_pipe(dev) \
368c2ecf20Sopenharmony_ci	usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE)
378c2ecf20Sopenharmony_ci#define ar5523_data_rx_pipe(dev) \
388c2ecf20Sopenharmony_ci	usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define	AR5523_DATA_TIMEOUT	10000
418c2ecf20Sopenharmony_ci#define	AR5523_CMD_TIMEOUT	1000
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define AR5523_TX_DATA_COUNT		8
448c2ecf20Sopenharmony_ci#define AR5523_TX_DATA_RESTART_COUNT	2
458c2ecf20Sopenharmony_ci#define AR5523_RX_DATA_COUNT		16
468c2ecf20Sopenharmony_ci#define AR5523_RX_DATA_REFILL_COUNT	8
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define AR5523_CMD_ID	1
498c2ecf20Sopenharmony_ci#define AR5523_DATA_ID	2
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define AR5523_TX_WD_TIMEOUT	(HZ * 2)
528c2ecf20Sopenharmony_ci#define AR5523_FLUSH_TIMEOUT	(HZ * 3)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cienum AR5523_flags {
558c2ecf20Sopenharmony_ci	AR5523_HW_UP,
568c2ecf20Sopenharmony_ci	AR5523_USB_DISCONNECTED,
578c2ecf20Sopenharmony_ci	AR5523_CONNECTED
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct ar5523_tx_cmd {
618c2ecf20Sopenharmony_ci	struct ar5523		*ar;
628c2ecf20Sopenharmony_ci	struct urb		*urb_tx;
638c2ecf20Sopenharmony_ci	void			*buf_tx;
648c2ecf20Sopenharmony_ci	void			*odata;
658c2ecf20Sopenharmony_ci	int			olen;
668c2ecf20Sopenharmony_ci	int			flags;
678c2ecf20Sopenharmony_ci	int			res;
688c2ecf20Sopenharmony_ci	struct completion	done;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* This struct is placed in tx_info->driver_data. It must not be larger
728c2ecf20Sopenharmony_ci *  than IEEE80211_TX_INFO_DRIVER_DATA_SIZE.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistruct ar5523_tx_data {
758c2ecf20Sopenharmony_ci	struct list_head	list;
768c2ecf20Sopenharmony_ci	struct ar5523		*ar;
778c2ecf20Sopenharmony_ci	struct urb		*urb;
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistruct ar5523_rx_data {
818c2ecf20Sopenharmony_ci	struct	list_head	list;
828c2ecf20Sopenharmony_ci	struct ar5523		*ar;
838c2ecf20Sopenharmony_ci	struct urb		*urb;
848c2ecf20Sopenharmony_ci	struct sk_buff		*skb;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct ar5523 {
888c2ecf20Sopenharmony_ci	struct usb_device	*dev;
898c2ecf20Sopenharmony_ci	struct ieee80211_hw	*hw;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	unsigned long		flags;
928c2ecf20Sopenharmony_ci	struct mutex		mutex;
938c2ecf20Sopenharmony_ci	struct workqueue_struct *wq;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	struct ar5523_tx_cmd	tx_cmd;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	struct delayed_work	stat_work;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	struct timer_list	tx_wd_timer;
1008c2ecf20Sopenharmony_ci	struct work_struct	tx_wd_work;
1018c2ecf20Sopenharmony_ci	struct work_struct	tx_work;
1028c2ecf20Sopenharmony_ci	struct list_head	tx_queue_pending;
1038c2ecf20Sopenharmony_ci	struct list_head	tx_queue_submitted;
1048c2ecf20Sopenharmony_ci	spinlock_t		tx_data_list_lock;
1058c2ecf20Sopenharmony_ci	wait_queue_head_t	tx_flush_waitq;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Queued + Submitted TX frames */
1088c2ecf20Sopenharmony_ci	atomic_t		tx_nr_total;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/* Submitted TX frames */
1118c2ecf20Sopenharmony_ci	atomic_t		tx_nr_pending;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	void			*rx_cmd_buf;
1148c2ecf20Sopenharmony_ci	struct urb		*rx_cmd_urb;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	struct ar5523_rx_data	rx_data[AR5523_RX_DATA_COUNT];
1178c2ecf20Sopenharmony_ci	spinlock_t		rx_data_list_lock;
1188c2ecf20Sopenharmony_ci	struct list_head	rx_data_free;
1198c2ecf20Sopenharmony_ci	struct list_head	rx_data_used;
1208c2ecf20Sopenharmony_ci	atomic_t		rx_data_free_cnt;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	struct work_struct	rx_refill_work;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	unsigned int		rxbufsz;
1258c2ecf20Sopenharmony_ci	u8			serial[16];
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	struct ieee80211_channel channels[14];
1288c2ecf20Sopenharmony_ci	struct ieee80211_rate	rates[12];
1298c2ecf20Sopenharmony_ci	struct ieee80211_supported_band band;
1308c2ecf20Sopenharmony_ci	struct ieee80211_vif	*vif;
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* flags for sending firmware commands */
1348c2ecf20Sopenharmony_ci#define AR5523_CMD_FLAG_READ	(1 << 1)
1358c2ecf20Sopenharmony_ci#define AR5523_CMD_FLAG_MAGIC	(1 << 2)
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define ar5523_dbg(ar, format, arg...) \
1388c2ecf20Sopenharmony_ci	dev_dbg(&(ar)->dev->dev, format, ## arg)
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* On USB hot-unplug there can be a lot of URBs in flight and they'll all
1418c2ecf20Sopenharmony_ci * fail. Instead of dealing with them in every possible place just surpress
1428c2ecf20Sopenharmony_ci * any messages on USB disconnect.
1438c2ecf20Sopenharmony_ci */
1448c2ecf20Sopenharmony_ci#define ar5523_err(ar, format, arg...) \
1458c2ecf20Sopenharmony_cido { \
1468c2ecf20Sopenharmony_ci	if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \
1478c2ecf20Sopenharmony_ci		dev_err(&(ar)->dev->dev, format, ## arg); \
1488c2ecf20Sopenharmony_ci	} \
1498c2ecf20Sopenharmony_ci} while (0)
1508c2ecf20Sopenharmony_ci#define ar5523_info(ar, format, arg...)	\
1518c2ecf20Sopenharmony_ci	dev_info(&(ar)->dev->dev, format, ## arg)
152