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