1b7d572e1SPontus Fuchs /*
2b7d572e1SPontus Fuchs  * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
3b7d572e1SPontus Fuchs  * Copyright (c) 2006 Sam Leffler, Errno Consulting
4b7d572e1SPontus Fuchs  * Copyright (c) 2007 Christoph Hellwig <hch@lst.de>
5b7d572e1SPontus Fuchs  * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
6b7d572e1SPontus Fuchs  * Copyright (c) 2012 Pontus Fuchs <pontus.fuchs@gmail.com>
7b7d572e1SPontus Fuchs  *
8b7d572e1SPontus Fuchs  * Permission to use, copy, modify, and/or distribute this software for any
9b7d572e1SPontus Fuchs  * purpose with or without fee is hereby granted, provided that the above
10b7d572e1SPontus Fuchs  * copyright notice and this permission notice appear in all copies.
11b7d572e1SPontus Fuchs  *
12b7d572e1SPontus Fuchs  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13b7d572e1SPontus Fuchs  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14b7d572e1SPontus Fuchs  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15b7d572e1SPontus Fuchs  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16b7d572e1SPontus Fuchs  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17b7d572e1SPontus Fuchs  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18b7d572e1SPontus Fuchs  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19b7d572e1SPontus Fuchs  */
20b7d572e1SPontus Fuchs 
21b7d572e1SPontus Fuchs #define AR5523_FLAG_PRE_FIRMWARE	(1 << 0)
22b7d572e1SPontus Fuchs #define AR5523_FLAG_ABG			(1 << 1)
23b7d572e1SPontus Fuchs 
24b7d572e1SPontus Fuchs #define AR5523_FIRMWARE_FILE	"ar5523.bin"
25b7d572e1SPontus Fuchs 
26b7d572e1SPontus Fuchs #define AR5523_CMD_TX_PIPE	0x01
27b7d572e1SPontus Fuchs #define	AR5523_DATA_TX_PIPE	0x02
28b7d572e1SPontus Fuchs #define	AR5523_CMD_RX_PIPE	0x81
29b7d572e1SPontus Fuchs #define	AR5523_DATA_RX_PIPE	0x82
30b7d572e1SPontus Fuchs 
31b7d572e1SPontus Fuchs #define ar5523_cmd_tx_pipe(dev) \
32b7d572e1SPontus Fuchs 	usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE)
33b7d572e1SPontus Fuchs #define ar5523_data_tx_pipe(dev) \
34b7d572e1SPontus Fuchs 	usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE)
35b7d572e1SPontus Fuchs #define ar5523_cmd_rx_pipe(dev) \
36b7d572e1SPontus Fuchs 	usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE)
37b7d572e1SPontus Fuchs #define ar5523_data_rx_pipe(dev) \
38b7d572e1SPontus Fuchs 	usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE)
39b7d572e1SPontus Fuchs 
40b7d572e1SPontus Fuchs #define	AR5523_DATA_TIMEOUT	10000
41b7d572e1SPontus Fuchs #define	AR5523_CMD_TIMEOUT	1000
42b7d572e1SPontus Fuchs 
43b7d572e1SPontus Fuchs #define AR5523_TX_DATA_COUNT		8
44b7d572e1SPontus Fuchs #define AR5523_TX_DATA_RESTART_COUNT	2
45b7d572e1SPontus Fuchs #define AR5523_RX_DATA_COUNT		16
46b7d572e1SPontus Fuchs #define AR5523_RX_DATA_REFILL_COUNT	8
47b7d572e1SPontus Fuchs 
48b7d572e1SPontus Fuchs #define AR5523_CMD_ID	1
49b7d572e1SPontus Fuchs #define AR5523_DATA_ID	2
50b7d572e1SPontus Fuchs 
51b7d572e1SPontus Fuchs #define AR5523_TX_WD_TIMEOUT	(HZ * 2)
52b7d572e1SPontus Fuchs #define AR5523_FLUSH_TIMEOUT	(HZ * 3)
53b7d572e1SPontus Fuchs 
54b7d572e1SPontus Fuchs enum AR5523_flags {
55b7d572e1SPontus Fuchs 	AR5523_HW_UP,
56b7d572e1SPontus Fuchs 	AR5523_USB_DISCONNECTED,
57b7d572e1SPontus Fuchs 	AR5523_CONNECTED
58b7d572e1SPontus Fuchs };
59b7d572e1SPontus Fuchs 
60b7d572e1SPontus Fuchs struct ar5523_tx_cmd {
61b7d572e1SPontus Fuchs 	struct ar5523		*ar;
62b7d572e1SPontus Fuchs 	struct urb		*urb_tx;
63b7d572e1SPontus Fuchs 	void			*buf_tx;
64b7d572e1SPontus Fuchs 	void			*odata;
65b7d572e1SPontus Fuchs 	int			olen;
66b7d572e1SPontus Fuchs 	int			flags;
67b7d572e1SPontus Fuchs 	int			res;
68b7d572e1SPontus Fuchs 	struct completion	done;
69b7d572e1SPontus Fuchs };
70b7d572e1SPontus Fuchs 
71b7d572e1SPontus Fuchs /* This struct is placed in tx_info->driver_data. It must not be larger
72b7d572e1SPontus Fuchs  *  than IEEE80211_TX_INFO_DRIVER_DATA_SIZE.
73b7d572e1SPontus Fuchs  */
74b7d572e1SPontus Fuchs struct ar5523_tx_data {
75b7d572e1SPontus Fuchs 	struct list_head	list;
76b7d572e1SPontus Fuchs 	struct ar5523		*ar;
77b7d572e1SPontus Fuchs 	struct urb		*urb;
78b7d572e1SPontus Fuchs };
79b7d572e1SPontus Fuchs 
80b7d572e1SPontus Fuchs struct ar5523_rx_data {
81b7d572e1SPontus Fuchs 	struct	list_head	list;
82b7d572e1SPontus Fuchs 	struct ar5523		*ar;
83b7d572e1SPontus Fuchs 	struct urb		*urb;
84b7d572e1SPontus Fuchs 	struct sk_buff		*skb;
85b7d572e1SPontus Fuchs };
86b7d572e1SPontus Fuchs 
87b7d572e1SPontus Fuchs struct ar5523 {
88b7d572e1SPontus Fuchs 	struct usb_device	*dev;
89b7d572e1SPontus Fuchs 	struct ieee80211_hw	*hw;
90b7d572e1SPontus Fuchs 
91b7d572e1SPontus Fuchs 	unsigned long		flags;
92b7d572e1SPontus Fuchs 	struct mutex		mutex;
93b7d572e1SPontus Fuchs 	struct workqueue_struct *wq;
94b7d572e1SPontus Fuchs 
95b7d572e1SPontus Fuchs 	struct ar5523_tx_cmd	tx_cmd;
96b7d572e1SPontus Fuchs 
97b7d572e1SPontus Fuchs 	struct delayed_work	stat_work;
98b7d572e1SPontus Fuchs 
99b7d572e1SPontus Fuchs 	struct timer_list	tx_wd_timer;
100b7d572e1SPontus Fuchs 	struct work_struct	tx_wd_work;
101b7d572e1SPontus Fuchs 	struct work_struct	tx_work;
102b7d572e1SPontus Fuchs 	struct list_head	tx_queue_pending;
103b7d572e1SPontus Fuchs 	struct list_head	tx_queue_submitted;
104b7d572e1SPontus Fuchs 	spinlock_t		tx_data_list_lock;
105b7d572e1SPontus Fuchs 	wait_queue_head_t	tx_flush_waitq;
106b7d572e1SPontus Fuchs 
107b7d572e1SPontus Fuchs 	/* Queued + Submitted TX frames */
108b7d572e1SPontus Fuchs 	atomic_t		tx_nr_total;
109b7d572e1SPontus Fuchs 
110b7d572e1SPontus Fuchs 	/* Submitted TX frames */
111b7d572e1SPontus Fuchs 	atomic_t		tx_nr_pending;
112b7d572e1SPontus Fuchs 
113b7d572e1SPontus Fuchs 	void			*rx_cmd_buf;
114b7d572e1SPontus Fuchs 	struct urb		*rx_cmd_urb;
115b7d572e1SPontus Fuchs 
116b7d572e1SPontus Fuchs 	struct ar5523_rx_data	rx_data[AR5523_RX_DATA_COUNT];
117b7d572e1SPontus Fuchs 	spinlock_t		rx_data_list_lock;
118b7d572e1SPontus Fuchs 	struct list_head	rx_data_free;
119b7d572e1SPontus Fuchs 	struct list_head	rx_data_used;
120b7d572e1SPontus Fuchs 	atomic_t		rx_data_free_cnt;
121b7d572e1SPontus Fuchs 
122b7d572e1SPontus Fuchs 	struct work_struct	rx_refill_work;
123b7d572e1SPontus Fuchs 
12438141fcfSDan Carpenter 	unsigned int		rxbufsz;
125b7d572e1SPontus Fuchs 	u8			serial[16];
126b7d572e1SPontus Fuchs 
127b7d572e1SPontus Fuchs 	struct ieee80211_channel channels[14];
128b7d572e1SPontus Fuchs 	struct ieee80211_rate	rates[12];
129b7d572e1SPontus Fuchs 	struct ieee80211_supported_band band;
130b7d572e1SPontus Fuchs 	struct ieee80211_vif	*vif;
131b7d572e1SPontus Fuchs };
132b7d572e1SPontus Fuchs 
133b7d572e1SPontus Fuchs /* flags for sending firmware commands */
134b7d572e1SPontus Fuchs #define AR5523_CMD_FLAG_READ	(1 << 1)
135b7d572e1SPontus Fuchs #define AR5523_CMD_FLAG_MAGIC	(1 << 2)
136b7d572e1SPontus Fuchs 
137b7d572e1SPontus Fuchs #define ar5523_dbg(ar, format, arg...) \
138b7d572e1SPontus Fuchs 	dev_dbg(&(ar)->dev->dev, format, ## arg)
139b7d572e1SPontus Fuchs 
140b7d572e1SPontus Fuchs /* On USB hot-unplug there can be a lot of URBs in flight and they'll all
141b7d572e1SPontus Fuchs  * fail. Instead of dealing with them in every possible place just surpress
142b7d572e1SPontus Fuchs  * any messages on USB disconnect.
143b7d572e1SPontus Fuchs  */
144b7d572e1SPontus Fuchs #define ar5523_err(ar, format, arg...) \
145b7d572e1SPontus Fuchs do { \
146b7d572e1SPontus Fuchs 	if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \
147b7d572e1SPontus Fuchs 		dev_err(&(ar)->dev->dev, format, ## arg); \
148b7d572e1SPontus Fuchs 	} \
149b7d572e1SPontus Fuchs } while (0)
150b7d572e1SPontus Fuchs #define ar5523_info(ar, format, arg...)	\
151b7d572e1SPontus Fuchs 	dev_info(&(ar)->dev->dev, format, ## arg)
152