Commit | Line | Data |
---|---|---|
3d97ca7f MB |
1 | /*===================================================== |
2 | * CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. | |
3 | * | |
4 | * | |
5 | * This file is part of Express Card USB Driver | |
6 | * | |
7 | * $Id: | |
8 | *==================================================== | |
9 | */ | |
f7c1be0c MB |
10 | #include <linux/init.h> |
11 | #include <linux/kernel.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/usb.h> | |
14 | #include <linux/netdevice.h> | |
15 | #include <linux/etherdevice.h> | |
ada541f0 | 16 | #include <linux/firmware.h> |
f7c1be0c MB |
17 | #include "ft1000_usb.h" |
18 | ||
f7c1be0c MB |
19 | #include <linux/kthread.h> |
20 | ||
21 | MODULE_DESCRIPTION("FT1000 EXPRESS CARD DRIVER"); | |
22 | MODULE_LICENSE("Dual MPL/GPL"); | |
23 | MODULE_SUPPORTED_DEVICE("QFT FT1000 Express Cards"); | |
24 | ||
f7c1be0c | 25 | void *pFileStart; |
2a953cfd | 26 | size_t FileLength; |
f7c1be0c | 27 | |
47873d33 MB |
28 | #define VENDOR_ID 0x1291 /* Qualcomm vendor id */ |
29 | #define PRODUCT_ID 0x11 /* fake product id */ | |
f7c1be0c MB |
30 | |
31 | /* table of devices that work with this driver */ | |
32 | static struct usb_device_id id_table[] = { | |
47873d33 MB |
33 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, |
34 | {}, | |
f7c1be0c MB |
35 | }; |
36 | ||
0f570d8c | 37 | MODULE_DEVICE_TABLE(usb, id_table); |
f7c1be0c | 38 | |
81584137 | 39 | static bool gPollingfailed = FALSE; |
3bc2311e | 40 | static int ft1000_poll_thread(void *arg) |
f7c1be0c | 41 | { |
b7c5a774 | 42 | int ret; |
47873d33 MB |
43 | |
44 | while (!kthread_should_stop()) { | |
45 | msleep(10); | |
46 | if (!gPollingfailed) { | |
47 | ret = ft1000_poll(arg); | |
48 | if (ret != STATUS_SUCCESS) { | |
49 | DEBUG("ft1000_poll_thread: polling failed\n"); | |
50 | gPollingfailed = TRUE; | |
51 | } | |
52 | } | |
53 | } | |
4aee92f6 | 54 | return STATUS_SUCCESS; |
f7c1be0c MB |
55 | } |
56 | ||
c6f2c47b MB |
57 | static int ft1000_probe(struct usb_interface *interface, |
58 | const struct usb_device_id *id) | |
f7c1be0c | 59 | { |
47873d33 MB |
60 | struct usb_host_interface *iface_desc; |
61 | struct usb_endpoint_descriptor *endpoint; | |
62 | struct usb_device *dev; | |
63 | unsigned numaltsetting; | |
ada541f0 | 64 | int i, ret = 0, size; |
f7c1be0c | 65 | |
47873d33 | 66 | struct ft1000_device *ft1000dev; |
7716090b | 67 | struct ft1000_info *pft1000info = NULL; |
ada541f0 MB |
68 | const struct firmware *dsp_fw; |
69 | ||
42ad4a8d | 70 | ft1000dev = kzalloc(sizeof(struct ft1000_device), GFP_KERNEL); |
0f570d8c MB |
71 | |
72 | if (!ft1000dev) { | |
626888df | 73 | pr_err("out of memory allocating device structure\n"); |
b10c0b92 | 74 | return -ENOMEM; |
0f570d8c | 75 | } |
f7c1be0c | 76 | |
47873d33 MB |
77 | dev = interface_to_usbdev(interface); |
78 | DEBUG("ft1000_probe: usb device descriptor info:\n"); | |
c6f2c47b MB |
79 | DEBUG("ft1000_probe: number of configuration is %d\n", |
80 | dev->descriptor.bNumConfigurations); | |
f7c1be0c MB |
81 | |
82 | ft1000dev->dev = dev; | |
83 | ft1000dev->status = 0; | |
84 | ft1000dev->net = NULL; | |
f7c1be0c MB |
85 | ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC); |
86 | ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC); | |
87 | ||
47873d33 MB |
88 | DEBUG("ft1000_probe is called\n"); |
89 | numaltsetting = interface->num_altsetting; | |
90 | DEBUG("ft1000_probe: number of alt settings is :%d\n", numaltsetting); | |
91 | iface_desc = interface->cur_altsetting; | |
c6f2c47b MB |
92 | DEBUG("ft1000_probe: number of endpoints is %d\n", |
93 | iface_desc->desc.bNumEndpoints); | |
94 | DEBUG("ft1000_probe: descriptor type is %d\n", | |
95 | iface_desc->desc.bDescriptorType); | |
96 | DEBUG("ft1000_probe: interface number is %d\n", | |
97 | iface_desc->desc.bInterfaceNumber); | |
98 | DEBUG("ft1000_probe: alternatesetting is %d\n", | |
99 | iface_desc->desc.bAlternateSetting); | |
100 | DEBUG("ft1000_probe: interface class is %d\n", | |
101 | iface_desc->desc.bInterfaceClass); | |
47873d33 | 102 | DEBUG("ft1000_probe: control endpoint info:\n"); |
c6f2c47b MB |
103 | DEBUG("ft1000_probe: descriptor0 type -- %d\n", |
104 | iface_desc->endpoint[0].desc.bmAttributes); | |
105 | DEBUG("ft1000_probe: descriptor1 type -- %d\n", | |
106 | iface_desc->endpoint[1].desc.bmAttributes); | |
107 | DEBUG("ft1000_probe: descriptor2 type -- %d\n", | |
108 | iface_desc->endpoint[2].desc.bmAttributes); | |
f7c1be0c | 109 | |
47873d33 | 110 | for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { |
c6f2c47b | 111 | endpoint = |
47873d33 MB |
112 | (struct usb_endpoint_descriptor *)&iface_desc-> |
113 | endpoint[i].desc; | |
114 | DEBUG("endpoint %d\n", i); | |
c6f2c47b MB |
115 | DEBUG("bEndpointAddress=%x, bmAttributes=%x\n", |
116 | endpoint->bEndpointAddress, endpoint->bmAttributes); | |
117 | if ((endpoint->bEndpointAddress & USB_DIR_IN) | |
118 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | |
119 | USB_ENDPOINT_XFER_BULK)) { | |
120 | ft1000dev->bulk_in_endpointAddr = | |
47873d33 | 121 | endpoint->bEndpointAddress; |
c6f2c47b MB |
122 | DEBUG("ft1000_probe: in: %d\n", |
123 | endpoint->bEndpointAddress); | |
f7c1be0c MB |
124 | } |
125 | ||
c6f2c47b MB |
126 | if (!(endpoint->bEndpointAddress & USB_DIR_IN) |
127 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | |
128 | USB_ENDPOINT_XFER_BULK)) { | |
129 | ft1000dev->bulk_out_endpointAddr = | |
47873d33 | 130 | endpoint->bEndpointAddress; |
c6f2c47b MB |
131 | DEBUG("ft1000_probe: out: %d\n", |
132 | endpoint->bEndpointAddress); | |
f7c1be0c | 133 | } |
47873d33 | 134 | } |
bf3146c8 | 135 | |
c6f2c47b MB |
136 | DEBUG("bulk_in=%d, bulk_out=%d\n", ft1000dev->bulk_in_endpointAddr, |
137 | ft1000dev->bulk_out_endpointAddr); | |
f7c1be0c | 138 | |
ada541f0 MB |
139 | ret = request_firmware(&dsp_fw, "ft3000.img", &dev->dev); |
140 | if (ret < 0) { | |
626888df | 141 | pr_err("Error request_firmware().\n"); |
ada541f0 MB |
142 | goto err_fw; |
143 | } | |
f7c1be0c | 144 | |
ada541f0 MB |
145 | size = max_t(uint, dsp_fw->size, 4096); |
146 | pFileStart = kmalloc(size, GFP_KERNEL); | |
147 | ||
148 | if (!pFileStart) { | |
149 | release_firmware(dsp_fw); | |
150 | ret = -ENOMEM; | |
151 | goto err_fw; | |
152 | } | |
153 | ||
154 | memcpy(pFileStart, dsp_fw->data, dsp_fw->size); | |
155 | FileLength = dsp_fw->size; | |
156 | release_firmware(dsp_fw); | |
f7c1be0c | 157 | |
47873d33 | 158 | DEBUG("ft1000_probe: start downloading dsp image...\n"); |
dd9b6aa4 MB |
159 | |
160 | ret = init_ft1000_netdev(ft1000dev); | |
161 | if (ret) | |
162 | goto err_load; | |
163 | ||
e33196e1 | 164 | pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c | 165 | |
4aee92f6 | 166 | DEBUG("In probe: pft1000info=%p\n", pft1000info); |
5cb9954a MB |
167 | ret = dsp_reload(ft1000dev); |
168 | if (ret) { | |
626888df | 169 | pr_err("Problem with DSP image loading\n"); |
5cb9954a MB |
170 | goto err_load; |
171 | } | |
172 | ||
4aee92f6 | 173 | gPollingfailed = FALSE; |
c6f2c47b MB |
174 | pft1000info->pPollThread = |
175 | kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll"); | |
c8b124e2 MB |
176 | |
177 | if (IS_ERR(pft1000info->pPollThread)) { | |
178 | ret = PTR_ERR(pft1000info->pPollThread); | |
e72115bc | 179 | goto err_load; |
c8b124e2 MB |
180 | } |
181 | ||
4aee92f6 | 182 | msleep(500); |
bf3146c8 | 183 | |
0f570d8c MB |
184 | while (!pft1000info->CardReady) { |
185 | if (gPollingfailed) { | |
0f570d8c | 186 | ret = -EIO; |
e72115bc | 187 | goto err_thread; |
0f570d8c MB |
188 | } |
189 | msleep(100); | |
190 | DEBUG("ft1000_probe::Waiting for Card Ready\n"); | |
191 | } | |
bf3146c8 | 192 | |
47873d33 | 193 | DEBUG("ft1000_probe::Card Ready!!!! Registering network device\n"); |
bf3146c8 | 194 | |
aaf0885c MB |
195 | ret = reg_ft1000_netdev(ft1000dev, interface); |
196 | if (ret) | |
e72115bc | 197 | goto err_thread; |
bf3146c8 | 198 | |
dab56ffe | 199 | ret = ft1000_init_proc(ft1000dev->net); |
1c462824 MB |
200 | if (ret) |
201 | goto err_proc; | |
f7c1be0c | 202 | |
1c462824 | 203 | pft1000info->NetDevRegDone = 1; |
f7c1be0c | 204 | |
47873d33 | 205 | return 0; |
ada541f0 | 206 | |
1c462824 MB |
207 | err_proc: |
208 | unregister_netdev(ft1000dev->net); | |
209 | free_netdev(ft1000dev->net); | |
2dab1ac8 | 210 | err_thread: |
4960b8fe MB |
211 | kthread_stop(pft1000info->pPollThread); |
212 | err_load: | |
5cb9954a | 213 | kfree(pFileStart); |
ada541f0 MB |
214 | err_fw: |
215 | kfree(ft1000dev); | |
216 | return ret; | |
f7c1be0c MB |
217 | } |
218 | ||
f7c1be0c MB |
219 | static void ft1000_disconnect(struct usb_interface *interface) |
220 | { | |
1a88a068 | 221 | struct ft1000_info *pft1000info; |
bf3146c8 | 222 | |
47873d33 | 223 | DEBUG("ft1000_disconnect is called\n"); |
bf3146c8 | 224 | |
1a88a068 | 225 | pft1000info = (struct ft1000_info *) usb_get_intfdata(interface); |
4aee92f6 | 226 | DEBUG("In disconnect pft1000info=%p\n", pft1000info); |
f7c1be0c | 227 | |
47873d33 | 228 | if (pft1000info) { |
dab56ffe | 229 | ft1000_cleanup_proc(pft1000info); |
47873d33 MB |
230 | if (pft1000info->pPollThread) |
231 | kthread_stop(pft1000info->pPollThread); | |
bf3146c8 | 232 | |
47873d33 | 233 | DEBUG("ft1000_disconnect: threads are terminated\n"); |
bf3146c8 | 234 | |
47873d33 MB |
235 | if (pft1000info->pFt1000Dev->net) { |
236 | DEBUG("ft1000_disconnect: destroy char driver\n"); | |
4d791234 | 237 | ft1000_destroy_dev(pft1000info->pFt1000Dev->net); |
47873d33 MB |
238 | unregister_netdev(pft1000info->pFt1000Dev->net); |
239 | DEBUG | |
aaf3ee4f | 240 | ("ft1000_disconnect: network device unregistered\n"); |
47873d33 | 241 | free_netdev(pft1000info->pFt1000Dev->net); |
f7c1be0c | 242 | |
47873d33 | 243 | } |
bf3146c8 | 244 | |
47873d33 MB |
245 | usb_free_urb(pft1000info->pFt1000Dev->rx_urb); |
246 | usb_free_urb(pft1000info->pFt1000Dev->tx_urb); | |
bf3146c8 | 247 | |
47873d33 | 248 | DEBUG("ft1000_disconnect: urb freed\n"); |
f7c1be0c | 249 | |
4aee92f6 | 250 | kfree(pft1000info->pFt1000Dev); |
47873d33 | 251 | } |
ada541f0 | 252 | kfree(pFileStart); |
f7c1be0c | 253 | |
47873d33 | 254 | return; |
f7c1be0c MB |
255 | } |
256 | ||
257 | static struct usb_driver ft1000_usb_driver = { | |
47873d33 MB |
258 | .name = "ft1000usb", |
259 | .probe = ft1000_probe, | |
260 | .disconnect = ft1000_disconnect, | |
261 | .id_table = id_table, | |
f7c1be0c MB |
262 | }; |
263 | ||
bac2c126 | 264 | module_usb_driver(ft1000_usb_driver); |