diff options
author | Alexander Holler <holler@ahsoftware.de> | 2010-11-22 15:09:01 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-01-19 11:40:41 -0500 |
commit | 86e09287e4f8c81831b4d4118a48597565f0d21b (patch) | |
tree | 90219f2e2b21c08170e8889a361f3c8cead6acb9 /drivers/bluetooth/ath3k.c | |
parent | 38d59392b29437af3a702209b6a5196ef01f79a8 (diff) |
Bluetooth: ath3k: reduce memory usage
There is no need to hold the firmware in memory.
Signed-off-by: Alexander Holler <holler@ahsoftware.de>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'drivers/bluetooth/ath3k.c')
-rw-r--r-- | drivers/bluetooth/ath3k.c | 75 |
1 files changed, 20 insertions, 55 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 949ed09c6361..a126e614601f 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c | |||
@@ -47,46 +47,40 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); | |||
47 | #define USB_REQ_DFU_DNLOAD 1 | 47 | #define USB_REQ_DFU_DNLOAD 1 |
48 | #define BULK_SIZE 4096 | 48 | #define BULK_SIZE 4096 |
49 | 49 | ||
50 | struct ath3k_data { | 50 | static int ath3k_load_firmware(struct usb_device *udev, |
51 | struct usb_device *udev; | 51 | const struct firmware *firmware) |
52 | u8 *fw_data; | ||
53 | u32 fw_size; | ||
54 | u32 fw_sent; | ||
55 | }; | ||
56 | |||
57 | static int ath3k_load_firmware(struct ath3k_data *data, | ||
58 | unsigned char *firmware, | ||
59 | int count) | ||
60 | { | 52 | { |
61 | u8 *send_buf; | 53 | u8 *send_buf; |
62 | int err, pipe, len, size, sent = 0; | 54 | int err, pipe, len, size, sent = 0; |
55 | int count = firmware->size; | ||
63 | 56 | ||
64 | BT_DBG("ath3k %p udev %p", data, data->udev); | 57 | BT_DBG("udev %p", udev); |
65 | 58 | ||
66 | pipe = usb_sndctrlpipe(data->udev, 0); | 59 | pipe = usb_sndctrlpipe(udev, 0); |
67 | 60 | ||
68 | if ((usb_control_msg(data->udev, pipe, | 61 | send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); |
62 | if (!send_buf) { | ||
63 | BT_ERR("Can't allocate memory chunk for firmware"); | ||
64 | return -ENOMEM; | ||
65 | } | ||
66 | |||
67 | memcpy(send_buf, firmware->data, 20); | ||
68 | if ((err = usb_control_msg(udev, pipe, | ||
69 | USB_REQ_DFU_DNLOAD, | 69 | USB_REQ_DFU_DNLOAD, |
70 | USB_TYPE_VENDOR, 0, 0, | 70 | USB_TYPE_VENDOR, 0, 0, |
71 | firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) { | 71 | send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) { |
72 | BT_ERR("Can't change to loading configuration err"); | 72 | BT_ERR("Can't change to loading configuration err"); |
73 | return -EBUSY; | 73 | goto error; |
74 | } | 74 | } |
75 | sent += 20; | 75 | sent += 20; |
76 | count -= 20; | 76 | count -= 20; |
77 | 77 | ||
78 | send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); | ||
79 | if (!send_buf) { | ||
80 | BT_ERR("Can't allocate memory chunk for firmware"); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | while (count) { | 78 | while (count) { |
85 | size = min_t(uint, count, BULK_SIZE); | 79 | size = min_t(uint, count, BULK_SIZE); |
86 | pipe = usb_sndbulkpipe(data->udev, 0x02); | 80 | pipe = usb_sndbulkpipe(udev, 0x02); |
87 | memcpy(send_buf, firmware + sent, size); | 81 | memcpy(send_buf, firmware->data + sent, size); |
88 | 82 | ||
89 | err = usb_bulk_msg(data->udev, pipe, send_buf, size, | 83 | err = usb_bulk_msg(udev, pipe, send_buf, size, |
90 | &len, 3000); | 84 | &len, 3000); |
91 | 85 | ||
92 | if (err || (len != size)) { | 86 | if (err || (len != size)) { |
@@ -112,57 +106,28 @@ static int ath3k_probe(struct usb_interface *intf, | |||
112 | { | 106 | { |
113 | const struct firmware *firmware; | 107 | const struct firmware *firmware; |
114 | struct usb_device *udev = interface_to_usbdev(intf); | 108 | struct usb_device *udev = interface_to_usbdev(intf); |
115 | struct ath3k_data *data; | ||
116 | int size; | ||
117 | 109 | ||
118 | BT_DBG("intf %p id %p", intf, id); | 110 | BT_DBG("intf %p id %p", intf, id); |
119 | 111 | ||
120 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) | 112 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
121 | return -ENODEV; | 113 | return -ENODEV; |
122 | 114 | ||
123 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
124 | if (!data) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | data->udev = udev; | ||
128 | |||
129 | if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) { | 115 | if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) { |
130 | kfree(data); | ||
131 | return -EIO; | 116 | return -EIO; |
132 | } | 117 | } |
133 | 118 | ||
134 | size = max_t(uint, firmware->size, 4096); | 119 | if (ath3k_load_firmware(udev, firmware)) { |
135 | data->fw_data = kmalloc(size, GFP_KERNEL); | ||
136 | if (!data->fw_data) { | ||
137 | release_firmware(firmware); | 120 | release_firmware(firmware); |
138 | kfree(data); | ||
139 | return -ENOMEM; | ||
140 | } | ||
141 | |||
142 | memcpy(data->fw_data, firmware->data, firmware->size); | ||
143 | data->fw_size = firmware->size; | ||
144 | data->fw_sent = 0; | ||
145 | release_firmware(firmware); | ||
146 | |||
147 | usb_set_intfdata(intf, data); | ||
148 | if (ath3k_load_firmware(data, data->fw_data, data->fw_size)) { | ||
149 | usb_set_intfdata(intf, NULL); | ||
150 | kfree(data->fw_data); | ||
151 | kfree(data); | ||
152 | return -EIO; | 121 | return -EIO; |
153 | } | 122 | } |
123 | release_firmware(firmware); | ||
154 | 124 | ||
155 | return 0; | 125 | return 0; |
156 | } | 126 | } |
157 | 127 | ||
158 | static void ath3k_disconnect(struct usb_interface *intf) | 128 | static void ath3k_disconnect(struct usb_interface *intf) |
159 | { | 129 | { |
160 | struct ath3k_data *data = usb_get_intfdata(intf); | ||
161 | |||
162 | BT_DBG("ath3k_disconnect intf %p", intf); | 130 | BT_DBG("ath3k_disconnect intf %p", intf); |
163 | |||
164 | kfree(data->fw_data); | ||
165 | kfree(data); | ||
166 | } | 131 | } |
167 | 132 | ||
168 | static struct usb_driver ath3k_driver = { | 133 | static struct usb_driver ath3k_driver = { |