ath3k.c revision 509e7861d8a5e26bb07b5a3a13e2b9e442283631
19670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri/*
29670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri * Copyright (c) 2008-2009 Atheros Communications Inc.
39670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *
49670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  This program is free software; you can redistribute it and/or modify
59670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  it under the terms of the GNU General Public License as published by
69670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  the Free Software Foundation; either version 2 of the License, or
79670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  (at your option) any later version.
89670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *
99670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  This program is distributed in the hope that it will be useful,
109670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  but WITHOUT ANY WARRANTY; without even the implied warranty of
119670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
129670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  GNU General Public License for more details.
139670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *
149670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  You should have received a copy of the GNU General Public License
159670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  along with this program; if not, write to the Free Software
169670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
179670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri *
189670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri */
199670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
209670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
219670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/module.h>
229670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/kernel.h>
239670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/init.h>
249670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/slab.h>
259670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/types.h>
269670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/errno.h>
279670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/device.h>
289670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/firmware.h>
299670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <linux/usb.h>
309670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#include <net/bluetooth/bluetooth.h>
319670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
329670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#define VERSION "1.0"
339670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
349670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
359670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic struct usb_device_id ath3k_table[] = {
369670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	/* Atheros AR3011 */
379670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	{ USB_DEVICE(0x0CF3, 0x3000) },
38be93112accb42c5586a459683d71975cc70673caBala Shanmugam
39be93112accb42c5586a459683d71975cc70673caBala Shanmugam	/* Atheros AR3011 with sflash firmware*/
40be93112accb42c5586a459683d71975cc70673caBala Shanmugam	{ USB_DEVICE(0x0CF3, 0x3002) },
41be93112accb42c5586a459683d71975cc70673caBala Shanmugam
42509e7861d8a5e26bb07b5a3a13e2b9e442283631Cho, Yu-Chen	/* Atheros AR9285 Malbec with sflash firmware */
43509e7861d8a5e26bb07b5a3a13e2b9e442283631Cho, Yu-Chen	{ USB_DEVICE(0x03F0, 0x311D) },
449670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	{ }	/* Terminating entry */
459670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri};
469670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
479670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_DEVICE_TABLE(usb, ath3k_table);
489670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
499670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#define USB_REQ_DFU_DNLOAD	1
509670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri#define BULK_SIZE		4096
519670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
5286e09287e4f8c81831b4d4118a48597565f0d21bAlexander Hollerstatic int ath3k_load_firmware(struct usb_device *udev,
5386e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler				const struct firmware *firmware)
549670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri{
559670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	u8 *send_buf;
569670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	int err, pipe, len, size, sent = 0;
5786e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	int count = firmware->size;
589670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
5986e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	BT_DBG("udev %p", udev);
609670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
6186e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	pipe = usb_sndctrlpipe(udev, 0);
629670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
6386e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
6486e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	if (!send_buf) {
6586e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		BT_ERR("Can't allocate memory chunk for firmware");
6686e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		return -ENOMEM;
6786e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	}
6886e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler
6986e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	memcpy(send_buf, firmware->data, 20);
7086e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	if ((err = usb_control_msg(udev, pipe,
719670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri				USB_REQ_DFU_DNLOAD,
729670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri				USB_TYPE_VENDOR, 0, 0,
7386e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler				send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
749670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		BT_ERR("Can't change to loading configuration err");
7586e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		goto error;
769670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	}
779670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	sent += 20;
789670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	count -= 20;
799670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
809670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	while (count) {
819670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		size = min_t(uint, count, BULK_SIZE);
8286e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		pipe = usb_sndbulkpipe(udev, 0x02);
8386e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		memcpy(send_buf, firmware->data + sent, size);
849670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
8586e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler		err = usb_bulk_msg(udev, pipe, send_buf, size,
869670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri					&len, 3000);
879670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
889670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		if (err || (len != size)) {
899670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri			BT_ERR("Error in firmware loading err = %d,"
909670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri				"len = %d, size = %d", err, len, size);
919670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri			goto error;
929670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		}
939670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
949670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		sent  += size;
959670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		count -= size;
969670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	}
979670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
989670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	kfree(send_buf);
999670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	return 0;
1009670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1019670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukurierror:
1029670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	kfree(send_buf);
1039670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	return err;
1049670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri}
1059670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1069670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic int ath3k_probe(struct usb_interface *intf,
1079670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri			const struct usb_device_id *id)
1089670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri{
1099670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	const struct firmware *firmware;
1109670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	struct usb_device *udev = interface_to_usbdev(intf);
1119670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1129670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	BT_DBG("intf %p id %p", intf, id);
1139670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1149670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
1159670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		return -ENODEV;
1169670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1179670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
1189670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		return -EIO;
1199670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	}
1209670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
12186e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	if (ath3k_load_firmware(udev, firmware)) {
1229670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		release_firmware(firmware);
1239670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri		return -EIO;
1249670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	}
12586e09287e4f8c81831b4d4118a48597565f0d21bAlexander Holler	release_firmware(firmware);
1269670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1279670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	return 0;
1289670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri}
1299670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1309670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic void ath3k_disconnect(struct usb_interface *intf)
1319670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri{
1329670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	BT_DBG("ath3k_disconnect intf %p", intf);
1339670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri}
1349670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1359670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic struct usb_driver ath3k_driver = {
1369670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	.name		= "ath3k",
1379670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	.probe		= ath3k_probe,
1389670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	.disconnect	= ath3k_disconnect,
1399670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	.id_table	= ath3k_table,
1409670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri};
1419670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1429670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic int __init ath3k_init(void)
1439670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri{
1449670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	BT_INFO("Atheros AR30xx firmware driver ver %s", VERSION);
1459670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	return usb_register(&ath3k_driver);
1469670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri}
1479670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1489670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuristatic void __exit ath3k_exit(void)
1499670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri{
1509670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri	usb_deregister(&ath3k_driver);
1519670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri}
1529670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1539670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukurimodule_init(ath3k_init);
1549670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukurimodule_exit(ath3k_exit);
1559670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram Kandukuri
1569670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_AUTHOR("Atheros Communications");
1579670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_DESCRIPTION("Atheros AR30xx firmware driver");
1589670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_VERSION(VERSION);
1599670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_LICENSE("GPL");
1609670d80a9a6e24725c4111bef5d6cc7786ad0dc5Vikram KandukuriMODULE_FIRMWARE("ath3k-1.fw");
161