xref: /openbmc/linux/drivers/net/wireless/ath/ath6kl/usb.c (revision e1f12eb6)
1241b128bSKalle Valo /*
2241b128bSKalle Valo  * Copyright (c) 2007-2011 Atheros Communications Inc.
31b2df407SVasanthakumar Thiagarajan  * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
4241b128bSKalle Valo  *
5241b128bSKalle Valo  * Permission to use, copy, modify, and/or distribute this software for any
6241b128bSKalle Valo  * purpose with or without fee is hereby granted, provided that the above
7241b128bSKalle Valo  * copyright notice and this permission notice appear in all copies.
8241b128bSKalle Valo  *
9241b128bSKalle Valo  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10241b128bSKalle Valo  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11241b128bSKalle Valo  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12241b128bSKalle Valo  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13241b128bSKalle Valo  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14241b128bSKalle Valo  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15241b128bSKalle Valo  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16241b128bSKalle Valo  */
17241b128bSKalle Valo 
18241b128bSKalle Valo #include <linux/module.h>
19241b128bSKalle Valo #include <linux/usb.h>
20241b128bSKalle Valo 
21241b128bSKalle Valo #include "debug.h"
22241b128bSKalle Valo #include "core.h"
23241b128bSKalle Valo 
24241b128bSKalle Valo /* usb device object */
25241b128bSKalle Valo struct ath6kl_usb {
26241b128bSKalle Valo 	struct usb_device *udev;
27241b128bSKalle Valo 	struct usb_interface *interface;
28241b128bSKalle Valo 	u8 *diag_cmd_buffer;
29241b128bSKalle Valo 	u8 *diag_resp_buffer;
30241b128bSKalle Valo 	struct ath6kl *ar;
31241b128bSKalle Valo };
32241b128bSKalle Valo 
33241b128bSKalle Valo /* diagnostic command defnitions */
34241b128bSKalle Valo #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD        1
35241b128bSKalle Valo #define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP       2
36241b128bSKalle Valo #define ATH6KL_USB_CONTROL_REQ_DIAG_CMD            3
37241b128bSKalle Valo #define ATH6KL_USB_CONTROL_REQ_DIAG_RESP           4
38241b128bSKalle Valo 
39241b128bSKalle Valo #define ATH6KL_USB_CTRL_DIAG_CC_READ               0
40241b128bSKalle Valo #define ATH6KL_USB_CTRL_DIAG_CC_WRITE              1
41241b128bSKalle Valo 
42241b128bSKalle Valo struct ath6kl_usb_ctrl_diag_cmd_write {
43241b128bSKalle Valo 	__le32 cmd;
44241b128bSKalle Valo 	__le32 address;
45241b128bSKalle Valo 	__le32 value;
46241b128bSKalle Valo 	__le32 _pad[1];
47241b128bSKalle Valo } __packed;
48241b128bSKalle Valo 
49241b128bSKalle Valo struct ath6kl_usb_ctrl_diag_cmd_read {
50241b128bSKalle Valo 	__le32 cmd;
51241b128bSKalle Valo 	__le32 address;
52241b128bSKalle Valo } __packed;
53241b128bSKalle Valo 
54241b128bSKalle Valo struct ath6kl_usb_ctrl_diag_resp_read {
55241b128bSKalle Valo 	__le32 value;
56241b128bSKalle Valo } __packed;
57241b128bSKalle Valo 
58241b128bSKalle Valo #define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
59241b128bSKalle Valo #define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
60241b128bSKalle Valo 
61241b128bSKalle Valo static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
62241b128bSKalle Valo {
63241b128bSKalle Valo 	usb_set_intfdata(ar_usb->interface, NULL);
64241b128bSKalle Valo 
65241b128bSKalle Valo 	kfree(ar_usb->diag_cmd_buffer);
66241b128bSKalle Valo 	kfree(ar_usb->diag_resp_buffer);
67241b128bSKalle Valo 
68241b128bSKalle Valo 	kfree(ar_usb);
69241b128bSKalle Valo }
70241b128bSKalle Valo 
71241b128bSKalle Valo static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
72241b128bSKalle Valo {
73241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = NULL;
74241b128bSKalle Valo 	struct usb_device *dev = interface_to_usbdev(interface);
75241b128bSKalle Valo 	int status = 0;
76241b128bSKalle Valo 
77241b128bSKalle Valo 	ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
78241b128bSKalle Valo 	if (ar_usb == NULL)
79241b128bSKalle Valo 		goto fail_ath6kl_usb_create;
80241b128bSKalle Valo 
81241b128bSKalle Valo 	memset(ar_usb, 0, sizeof(struct ath6kl_usb));
82241b128bSKalle Valo 	usb_set_intfdata(interface, ar_usb);
83241b128bSKalle Valo 	ar_usb->udev = dev;
84241b128bSKalle Valo 	ar_usb->interface = interface;
85241b128bSKalle Valo 
86241b128bSKalle Valo 	ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
87241b128bSKalle Valo 	if (ar_usb->diag_cmd_buffer == NULL) {
88241b128bSKalle Valo 		status = -ENOMEM;
89241b128bSKalle Valo 		goto fail_ath6kl_usb_create;
90241b128bSKalle Valo 	}
91241b128bSKalle Valo 
92241b128bSKalle Valo 	ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP,
93241b128bSKalle Valo 					   GFP_KERNEL);
94241b128bSKalle Valo 	if (ar_usb->diag_resp_buffer == NULL) {
95241b128bSKalle Valo 		status = -ENOMEM;
96241b128bSKalle Valo 		goto fail_ath6kl_usb_create;
97241b128bSKalle Valo 	}
98241b128bSKalle Valo 
99241b128bSKalle Valo fail_ath6kl_usb_create:
100241b128bSKalle Valo 	if (status != 0) {
101241b128bSKalle Valo 		ath6kl_usb_destroy(ar_usb);
102241b128bSKalle Valo 		ar_usb = NULL;
103241b128bSKalle Valo 	}
104241b128bSKalle Valo 	return ar_usb;
105241b128bSKalle Valo }
106241b128bSKalle Valo 
107241b128bSKalle Valo static void ath6kl_usb_device_detached(struct usb_interface *interface)
108241b128bSKalle Valo {
109241b128bSKalle Valo 	struct ath6kl_usb *ar_usb;
110241b128bSKalle Valo 
111241b128bSKalle Valo 	ar_usb = usb_get_intfdata(interface);
112241b128bSKalle Valo 	if (ar_usb == NULL)
113241b128bSKalle Valo 		return;
114241b128bSKalle Valo 
115241b128bSKalle Valo 	ath6kl_stop_txrx(ar_usb->ar);
116241b128bSKalle Valo 
117241b128bSKalle Valo 	ath6kl_core_cleanup(ar_usb->ar);
118241b128bSKalle Valo 
119241b128bSKalle Valo 	ath6kl_usb_destroy(ar_usb);
120241b128bSKalle Valo }
121241b128bSKalle Valo 
122241b128bSKalle Valo static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
123241b128bSKalle Valo 				   u8 req, u16 value, u16 index, void *data,
124241b128bSKalle Valo 				   u32 size)
125241b128bSKalle Valo {
126241b128bSKalle Valo 	u8 *buf = NULL;
127241b128bSKalle Valo 	int ret;
128241b128bSKalle Valo 
129241b128bSKalle Valo 	if (size > 0) {
130241b128bSKalle Valo 		buf = kmalloc(size, GFP_KERNEL);
131241b128bSKalle Valo 		if (buf == NULL)
132241b128bSKalle Valo 			return -ENOMEM;
133241b128bSKalle Valo 
134241b128bSKalle Valo 		memcpy(buf, data, size);
135241b128bSKalle Valo 	}
136241b128bSKalle Valo 
137241b128bSKalle Valo 	/* note: if successful returns number of bytes transfered */
138241b128bSKalle Valo 	ret = usb_control_msg(ar_usb->udev,
139241b128bSKalle Valo 			      usb_sndctrlpipe(ar_usb->udev, 0),
140241b128bSKalle Valo 			      req,
141241b128bSKalle Valo 			      USB_DIR_OUT | USB_TYPE_VENDOR |
142241b128bSKalle Valo 			      USB_RECIP_DEVICE, value, index, buf,
143241b128bSKalle Valo 			      size, 1000);
144241b128bSKalle Valo 
145241b128bSKalle Valo 	if (ret < 0) {
146241b128bSKalle Valo 		ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
147241b128bSKalle Valo 			   __func__, ret);
148241b128bSKalle Valo 	}
149241b128bSKalle Valo 
150241b128bSKalle Valo 	kfree(buf);
151241b128bSKalle Valo 
152241b128bSKalle Valo 	return 0;
153241b128bSKalle Valo }
154241b128bSKalle Valo 
155241b128bSKalle Valo static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
156241b128bSKalle Valo 				  u8 req, u16 value, u16 index, void *data,
157241b128bSKalle Valo 				  u32 size)
158241b128bSKalle Valo {
159241b128bSKalle Valo 	u8 *buf = NULL;
160241b128bSKalle Valo 	int ret;
161241b128bSKalle Valo 
162241b128bSKalle Valo 	if (size > 0) {
163241b128bSKalle Valo 		buf = kmalloc(size, GFP_KERNEL);
164241b128bSKalle Valo 		if (buf == NULL)
165241b128bSKalle Valo 			return -ENOMEM;
166241b128bSKalle Valo 	}
167241b128bSKalle Valo 
168241b128bSKalle Valo 	/* note: if successful returns number of bytes transfered */
169241b128bSKalle Valo 	ret = usb_control_msg(ar_usb->udev,
170241b128bSKalle Valo 				 usb_rcvctrlpipe(ar_usb->udev, 0),
171241b128bSKalle Valo 				 req,
172241b128bSKalle Valo 				 USB_DIR_IN | USB_TYPE_VENDOR |
173241b128bSKalle Valo 				 USB_RECIP_DEVICE, value, index, buf,
174241b128bSKalle Valo 				 size, 2 * HZ);
175241b128bSKalle Valo 
176241b128bSKalle Valo 	if (ret < 0) {
177241b128bSKalle Valo 		ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
178241b128bSKalle Valo 			   __func__, ret);
179241b128bSKalle Valo 	}
180241b128bSKalle Valo 
181241b128bSKalle Valo 	memcpy((u8 *) data, buf, size);
182241b128bSKalle Valo 
183241b128bSKalle Valo 	kfree(buf);
184241b128bSKalle Valo 
185241b128bSKalle Valo 	return 0;
186241b128bSKalle Valo }
187241b128bSKalle Valo 
188241b128bSKalle Valo static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb,
189241b128bSKalle Valo 				     u8 req_val, u8 *req_buf, u32 req_len,
190241b128bSKalle Valo 				     u8 resp_val, u8 *resp_buf, u32 *resp_len)
191241b128bSKalle Valo {
192241b128bSKalle Valo 	int ret;
193241b128bSKalle Valo 
194241b128bSKalle Valo 	/* send command */
195241b128bSKalle Valo 	ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0,
196241b128bSKalle Valo 					 req_buf, req_len);
197241b128bSKalle Valo 
198241b128bSKalle Valo 	if (ret != 0)
199241b128bSKalle Valo 		return ret;
200241b128bSKalle Valo 
201241b128bSKalle Valo 	if (resp_buf == NULL) {
202241b128bSKalle Valo 		/* no expected response */
203241b128bSKalle Valo 		return ret;
204241b128bSKalle Valo 	}
205241b128bSKalle Valo 
206241b128bSKalle Valo 	/* get response */
207241b128bSKalle Valo 	ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0,
208241b128bSKalle Valo 					resp_buf, *resp_len);
209241b128bSKalle Valo 
210241b128bSKalle Valo 	return ret;
211241b128bSKalle Valo }
212241b128bSKalle Valo 
213241b128bSKalle Valo static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
214241b128bSKalle Valo {
215241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = ar->hif_priv;
216241b128bSKalle Valo 	struct ath6kl_usb_ctrl_diag_resp_read *resp;
217241b128bSKalle Valo 	struct ath6kl_usb_ctrl_diag_cmd_read *cmd;
218241b128bSKalle Valo 	u32 resp_len;
219241b128bSKalle Valo 	int ret;
220241b128bSKalle Valo 
221241b128bSKalle Valo 	cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer;
222241b128bSKalle Valo 
223241b128bSKalle Valo 	memset(cmd, 0, sizeof(*cmd));
224241b128bSKalle Valo 	cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ;
225241b128bSKalle Valo 	cmd->address = cpu_to_le32(address);
226241b128bSKalle Valo 	resp_len = sizeof(*resp);
227241b128bSKalle Valo 
228241b128bSKalle Valo 	ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
229241b128bSKalle Valo 				ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
230241b128bSKalle Valo 				(u8 *) cmd,
231241b128bSKalle Valo 				sizeof(struct ath6kl_usb_ctrl_diag_cmd_write),
232241b128bSKalle Valo 				ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
233241b128bSKalle Valo 				ar_usb->diag_resp_buffer, &resp_len);
234241b128bSKalle Valo 
235241b128bSKalle Valo 	if (ret)
236241b128bSKalle Valo 		return ret;
237241b128bSKalle Valo 
238241b128bSKalle Valo 	resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
239241b128bSKalle Valo 		ar_usb->diag_resp_buffer;
240241b128bSKalle Valo 
241241b128bSKalle Valo 	*data = le32_to_cpu(resp->value);
242241b128bSKalle Valo 
243241b128bSKalle Valo 	return ret;
244241b128bSKalle Valo }
245241b128bSKalle Valo 
246241b128bSKalle Valo static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
247241b128bSKalle Valo {
248241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = ar->hif_priv;
249241b128bSKalle Valo 	struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
250241b128bSKalle Valo 
251241b128bSKalle Valo 	cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;
252241b128bSKalle Valo 
253241b128bSKalle Valo 	memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write));
254241b128bSKalle Valo 	cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE);
255241b128bSKalle Valo 	cmd->address = cpu_to_le32(address);
256241b128bSKalle Valo 	cmd->value = data;
257241b128bSKalle Valo 
258241b128bSKalle Valo 	return ath6kl_usb_ctrl_msg_exchange(ar_usb,
259241b128bSKalle Valo 					    ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
260241b128bSKalle Valo 					    (u8 *) cmd,
261241b128bSKalle Valo 					    sizeof(*cmd),
262241b128bSKalle Valo 					    0, NULL, NULL);
263241b128bSKalle Valo 
264241b128bSKalle Valo }
265241b128bSKalle Valo 
266241b128bSKalle Valo static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
267241b128bSKalle Valo {
268241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = ar->hif_priv;
269241b128bSKalle Valo 	int ret;
270241b128bSKalle Valo 
271241b128bSKalle Valo 	/* get response */
272241b128bSKalle Valo 	ret = ath6kl_usb_submit_ctrl_in(ar_usb,
273241b128bSKalle Valo 					ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
274241b128bSKalle Valo 					0, 0, buf, len);
275241b128bSKalle Valo 	if (ret != 0) {
276241b128bSKalle Valo 		ath6kl_err("Unable to read the bmi data from the device: %d\n",
277241b128bSKalle Valo 			   ret);
278241b128bSKalle Valo 		return ret;
279241b128bSKalle Valo 	}
280241b128bSKalle Valo 
281241b128bSKalle Valo 	return 0;
282241b128bSKalle Valo }
283241b128bSKalle Valo 
284241b128bSKalle Valo static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
285241b128bSKalle Valo {
286241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = ar->hif_priv;
287241b128bSKalle Valo 	int ret;
288241b128bSKalle Valo 
289241b128bSKalle Valo 	/* send command */
290241b128bSKalle Valo 	ret = ath6kl_usb_submit_ctrl_out(ar_usb,
291241b128bSKalle Valo 					 ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
292241b128bSKalle Valo 					 0, 0, buf, len);
293241b128bSKalle Valo 	if (ret != 0) {
294241b128bSKalle Valo 		ath6kl_err("unable to send the bmi data to the device: %d\n",
295241b128bSKalle Valo 			   ret);
296241b128bSKalle Valo 		return ret;
297241b128bSKalle Valo 	}
298241b128bSKalle Valo 
299241b128bSKalle Valo 	return 0;
300241b128bSKalle Valo }
301241b128bSKalle Valo 
302241b128bSKalle Valo static int ath6kl_usb_power_on(struct ath6kl *ar)
303241b128bSKalle Valo {
304241b128bSKalle Valo 	return 0;
305241b128bSKalle Valo }
306241b128bSKalle Valo 
307241b128bSKalle Valo static int ath6kl_usb_power_off(struct ath6kl *ar)
308241b128bSKalle Valo {
309241b128bSKalle Valo 	return 0;
310241b128bSKalle Valo }
311241b128bSKalle Valo 
312241b128bSKalle Valo static const struct ath6kl_hif_ops ath6kl_usb_ops = {
313241b128bSKalle Valo 	.diag_read32 = ath6kl_usb_diag_read32,
314241b128bSKalle Valo 	.diag_write32 = ath6kl_usb_diag_write32,
315241b128bSKalle Valo 	.bmi_read = ath6kl_usb_bmi_read,
316241b128bSKalle Valo 	.bmi_write = ath6kl_usb_bmi_write,
317241b128bSKalle Valo 	.power_on = ath6kl_usb_power_on,
318241b128bSKalle Valo 	.power_off = ath6kl_usb_power_off,
319241b128bSKalle Valo };
320241b128bSKalle Valo 
321241b128bSKalle Valo /* ath6kl usb driver registered functions */
322241b128bSKalle Valo static int ath6kl_usb_probe(struct usb_interface *interface,
323241b128bSKalle Valo 			    const struct usb_device_id *id)
324241b128bSKalle Valo {
325241b128bSKalle Valo 	struct usb_device *dev = interface_to_usbdev(interface);
326241b128bSKalle Valo 	struct ath6kl *ar;
327241b128bSKalle Valo 	struct ath6kl_usb *ar_usb = NULL;
328241b128bSKalle Valo 	int vendor_id, product_id;
329241b128bSKalle Valo 	int ret = 0;
330241b128bSKalle Valo 
331241b128bSKalle Valo 	usb_get_dev(dev);
332241b128bSKalle Valo 
333241b128bSKalle Valo 	vendor_id = le16_to_cpu(dev->descriptor.idVendor);
334241b128bSKalle Valo 	product_id = le16_to_cpu(dev->descriptor.idProduct);
335241b128bSKalle Valo 
336241b128bSKalle Valo 	ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id);
337241b128bSKalle Valo 	ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id);
338241b128bSKalle Valo 
339241b128bSKalle Valo 	if (interface->cur_altsetting)
340241b128bSKalle Valo 		ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n",
341241b128bSKalle Valo 			   interface->cur_altsetting->desc.bInterfaceNumber);
342241b128bSKalle Valo 
343241b128bSKalle Valo 
344241b128bSKalle Valo 	if (dev->speed == USB_SPEED_HIGH)
345241b128bSKalle Valo 		ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n");
346241b128bSKalle Valo 	else
347241b128bSKalle Valo 		ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n");
348241b128bSKalle Valo 
349241b128bSKalle Valo 	ar_usb = ath6kl_usb_create(interface);
350241b128bSKalle Valo 
351241b128bSKalle Valo 	if (ar_usb == NULL) {
352241b128bSKalle Valo 		ret = -ENOMEM;
353241b128bSKalle Valo 		goto err_usb_put;
354241b128bSKalle Valo 	}
355241b128bSKalle Valo 
356241b128bSKalle Valo 	ar = ath6kl_core_create(&ar_usb->udev->dev);
357241b128bSKalle Valo 	if (ar == NULL) {
358241b128bSKalle Valo 		ath6kl_err("Failed to alloc ath6kl core\n");
359241b128bSKalle Valo 		ret = -ENOMEM;
360241b128bSKalle Valo 		goto err_usb_destroy;
361241b128bSKalle Valo 	}
362241b128bSKalle Valo 
363241b128bSKalle Valo 	ar->hif_priv = ar_usb;
364241b128bSKalle Valo 	ar->hif_type = ATH6KL_HIF_TYPE_USB;
365241b128bSKalle Valo 	ar->hif_ops = &ath6kl_usb_ops;
366241b128bSKalle Valo 	ar->mbox_info.block_size = 16;
367241b128bSKalle Valo 	ar->bmi.max_data_size = 252;
368241b128bSKalle Valo 
369241b128bSKalle Valo 	ar_usb->ar = ar;
370241b128bSKalle Valo 
371241b128bSKalle Valo 	ret = ath6kl_core_init(ar);
372241b128bSKalle Valo 	if (ret) {
373241b128bSKalle Valo 		ath6kl_err("Failed to init ath6kl core: %d\n", ret);
374241b128bSKalle Valo 		goto err_core_free;
375241b128bSKalle Valo 	}
376241b128bSKalle Valo 
377241b128bSKalle Valo 	return ret;
378241b128bSKalle Valo 
379241b128bSKalle Valo err_core_free:
380241b128bSKalle Valo 	ath6kl_core_destroy(ar);
381241b128bSKalle Valo err_usb_destroy:
382241b128bSKalle Valo 	ath6kl_usb_destroy(ar_usb);
383241b128bSKalle Valo err_usb_put:
384241b128bSKalle Valo 	usb_put_dev(dev);
385241b128bSKalle Valo 
386241b128bSKalle Valo 	return ret;
387241b128bSKalle Valo }
388241b128bSKalle Valo 
389241b128bSKalle Valo static void ath6kl_usb_remove(struct usb_interface *interface)
390241b128bSKalle Valo {
391241b128bSKalle Valo 	usb_put_dev(interface_to_usbdev(interface));
392241b128bSKalle Valo 	ath6kl_usb_device_detached(interface);
393241b128bSKalle Valo }
394241b128bSKalle Valo 
395241b128bSKalle Valo /* table of devices that work with this driver */
396241b128bSKalle Valo static struct usb_device_id ath6kl_usb_ids[] = {
397241b128bSKalle Valo 	{USB_DEVICE(0x0cf3, 0x9374)},
398241b128bSKalle Valo 	{ /* Terminating entry */ },
399241b128bSKalle Valo };
400241b128bSKalle Valo 
401241b128bSKalle Valo MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
402241b128bSKalle Valo 
403241b128bSKalle Valo static struct usb_driver ath6kl_usb_driver = {
404241b128bSKalle Valo 	.name = "ath6kl_usb",
405241b128bSKalle Valo 	.probe = ath6kl_usb_probe,
406241b128bSKalle Valo 	.disconnect = ath6kl_usb_remove,
407241b128bSKalle Valo 	.id_table = ath6kl_usb_ids,
408e1f12eb6SSarah Sharp 	.disable_hub_initiated_lpm = 1,
409241b128bSKalle Valo };
410241b128bSKalle Valo 
411241b128bSKalle Valo static int ath6kl_usb_init(void)
412241b128bSKalle Valo {
413241b128bSKalle Valo 	usb_register(&ath6kl_usb_driver);
414241b128bSKalle Valo 	return 0;
415241b128bSKalle Valo }
416241b128bSKalle Valo 
417241b128bSKalle Valo static void ath6kl_usb_exit(void)
418241b128bSKalle Valo {
419241b128bSKalle Valo 	usb_deregister(&ath6kl_usb_driver);
420241b128bSKalle Valo }
421241b128bSKalle Valo 
422241b128bSKalle Valo module_init(ath6kl_usb_init);
423241b128bSKalle Valo module_exit(ath6kl_usb_exit);
424241b128bSKalle Valo 
425241b128bSKalle Valo MODULE_AUTHOR("Atheros Communications, Inc.");
426241b128bSKalle Valo MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
427241b128bSKalle Valo MODULE_LICENSE("Dual BSD/GPL");
428241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
429241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
430241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
431241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
432241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
433241b128bSKalle Valo MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
434