Commit | Line | Data |
---|---|---|
f7c1be0c 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 | // 20090926; aelias; removed all compiler warnings; ubuntu 9.04; 2.6.28-15-generic | |
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 | ||
19 | //#include <linux/sched.h> | |
20 | //#include <linux/ptrace.h> | |
21 | //#include <linux/slab.h> | |
22 | //#include <linux/string.h> | |
23 | //#include <linux/timer.h> | |
24 | //#include <linux/netdevice.h> | |
25 | //#include <linux/ioport.h> | |
26 | //#include <linux/delay.h> | |
27 | //#include <asm/io.h> | |
28 | //#include <asm/system.h> | |
29 | #include <linux/kthread.h> | |
30 | ||
31 | MODULE_DESCRIPTION("FT1000 EXPRESS CARD DRIVER"); | |
32 | MODULE_LICENSE("Dual MPL/GPL"); | |
33 | MODULE_SUPPORTED_DEVICE("QFT FT1000 Express Cards"); | |
34 | ||
35 | ||
36 | void *pFileStart; | |
2a953cfd | 37 | size_t FileLength; |
f7c1be0c MB |
38 | |
39 | #define VENDOR_ID 0x1291 /* Qualcomm vendor id */ | |
40 | #define PRODUCT_ID 0x11 /* fake product id */ | |
41 | ||
42 | /* table of devices that work with this driver */ | |
43 | static struct usb_device_id id_table[] = { | |
44 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, | |
45 | { }, | |
46 | }; | |
47 | ||
48 | MODULE_DEVICE_TABLE (usb, id_table); | |
49 | ||
2a953cfd | 50 | static BOOLEAN gPollingfailed = FALSE; |
f7c1be0c MB |
51 | int ft1000_poll_thread(void *arg) |
52 | { | |
53 | int ret = STATUS_SUCCESS; | |
54 | ||
55 | while(!kthread_should_stop() ) | |
56 | { | |
57 | msleep(10); | |
58 | if ( ! gPollingfailed ) | |
59 | { | |
bf3146c8 | 60 | ret = ft1000_poll(arg); |
f7c1be0c MB |
61 | if ( ret != STATUS_SUCCESS ) |
62 | { | |
63 | DEBUG("ft1000_poll_thread: polling failed\n"); | |
64 | gPollingfailed = TRUE; | |
65 | } | |
66 | } | |
67 | } | |
68 | //DEBUG("returned from polling thread\n"); | |
bf3146c8 | 69 | return STATUS_SUCCESS; |
f7c1be0c MB |
70 | } |
71 | ||
72 | ||
73 | ||
74 | //--------------------------------------------------------------------------- | |
75 | // Function: ft1000_probe | |
76 | // | |
77 | // Parameters: struct usb_interface *interface - passed by USB core | |
78 | // struct usb_device_id *id - passed by USB core | |
79 | // Returns: 0 - success | |
80 | // | |
81 | // Description: This function is invoked when the express card is plugged in | |
82 | // | |
83 | // Notes: | |
84 | // | |
85 | //--------------------------------------------------------------------------- | |
86 | static int ft1000_probe(struct usb_interface *interface, const struct usb_device_id *id) | |
87 | { | |
88 | struct usb_host_interface *iface_desc; | |
89 | struct usb_endpoint_descriptor *endpoint; | |
90 | struct usb_device *dev; | |
bf3146c8 | 91 | unsigned numaltsetting; |
ada541f0 | 92 | int i, ret = 0, size; |
f7c1be0c MB |
93 | |
94 | struct ft1000_device *ft1000dev; | |
95 | FT1000_INFO *pft1000info; | |
ada541f0 MB |
96 | const struct firmware *dsp_fw; |
97 | ||
f7c1be0c MB |
98 | |
99 | if(!(ft1000dev = kmalloc(sizeof(struct ft1000_device), GFP_KERNEL))) | |
100 | { | |
101 | printk("out of memory allocating device structure\n"); | |
102 | return 0; | |
103 | } | |
104 | ||
105 | memset(ft1000dev, 0, sizeof(*ft1000dev)); | |
bf3146c8 | 106 | |
f7c1be0c MB |
107 | //get usb device |
108 | dev = interface_to_usbdev(interface); | |
109 | DEBUG("ft1000_probe: usb device descriptor info:\n"); | |
110 | DEBUG("ft1000_probe: number of configuration is %d\n", dev->descriptor.bNumConfigurations); | |
111 | ||
112 | ft1000dev->dev = dev; | |
113 | ft1000dev->status = 0; | |
114 | ft1000dev->net = NULL; | |
115 | //ft1000dev->device_lock = SPIN_LOCK_UNLOCKED; | |
116 | spin_lock_init(&ft1000dev->device_lock); | |
117 | ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC); | |
118 | ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC); | |
119 | ||
120 | ||
121 | DEBUG("ft1000_probe is called\n"); | |
122 | numaltsetting = interface->num_altsetting; | |
bf3146c8 | 123 | DEBUG("ft1000_probe: number of alt settings is :%d\n",numaltsetting); |
f7c1be0c | 124 | iface_desc = interface->cur_altsetting; |
bf3146c8 | 125 | DEBUG("ft1000_probe: number of endpoints is %d\n", iface_desc->desc.bNumEndpoints); |
f7c1be0c MB |
126 | DEBUG("ft1000_probe: descriptor type is %d\n", iface_desc->desc.bDescriptorType); |
127 | DEBUG("ft1000_probe: interface number is %d\n", iface_desc->desc.bInterfaceNumber); | |
128 | DEBUG("ft1000_probe: alternatesetting is %d\n", iface_desc->desc.bAlternateSetting); | |
129 | DEBUG("ft1000_probe: interface class is %d\n", iface_desc->desc.bInterfaceClass); | |
130 | DEBUG("ft1000_probe: control endpoint info:\n"); | |
131 | DEBUG("ft1000_probe: descriptor0 type -- %d\n", iface_desc->endpoint[0].desc.bmAttributes); | |
132 | DEBUG("ft1000_probe: descriptor1 type -- %d\n", iface_desc->endpoint[1].desc.bmAttributes); | |
133 | DEBUG("ft1000_probe: descriptor2 type -- %d\n", iface_desc->endpoint[2].desc.bmAttributes); | |
134 | ||
135 | for (i=0; i< iface_desc->desc.bNumEndpoints;i++ ) | |
136 | { | |
137 | endpoint = (struct usb_endpoint_descriptor *)&iface_desc->endpoint[i].desc; | |
138 | DEBUG("endpoint %d\n", i); | |
139 | DEBUG("bEndpointAddress=%x, bmAttributes=%x\n", endpoint->bEndpointAddress, endpoint->bmAttributes); | |
bf3146c8 | 140 | if ( (endpoint->bEndpointAddress & USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) |
f7c1be0c MB |
141 | { |
142 | ft1000dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; | |
143 | DEBUG("ft1000_probe: in: %d\n", endpoint->bEndpointAddress); | |
144 | } | |
145 | ||
146 | if (!(endpoint->bEndpointAddress & USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) | |
147 | { | |
148 | ft1000dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; | |
149 | DEBUG("ft1000_probe: out: %d\n", endpoint->bEndpointAddress); | |
150 | } | |
151 | } | |
bf3146c8 | 152 | |
f7c1be0c MB |
153 | DEBUG("bulk_in=%d, bulk_out=%d\n", ft1000dev->bulk_in_endpointAddr, ft1000dev->bulk_out_endpointAddr); |
154 | ||
ada541f0 MB |
155 | ret = request_firmware(&dsp_fw, "ft3000.img", &dev->dev); |
156 | if (ret < 0) { | |
157 | printk(KERN_ERR "Error request_firmware().\n"); | |
158 | goto err_fw; | |
159 | } | |
f7c1be0c | 160 | |
ada541f0 MB |
161 | size = max_t(uint, dsp_fw->size, 4096); |
162 | pFileStart = kmalloc(size, GFP_KERNEL); | |
163 | ||
164 | if (!pFileStart) { | |
165 | release_firmware(dsp_fw); | |
166 | ret = -ENOMEM; | |
167 | goto err_fw; | |
168 | } | |
169 | ||
170 | memcpy(pFileStart, dsp_fw->data, dsp_fw->size); | |
171 | FileLength = dsp_fw->size; | |
172 | release_firmware(dsp_fw); | |
f7c1be0c MB |
173 | |
174 | //for ( i=0; i< MAX_NUM_CARDS+2; i++) | |
175 | // pdevobj[i] = NULL; | |
bf3146c8 | 176 | |
f7c1be0c MB |
177 | //download dsp image |
178 | DEBUG("ft1000_probe: start downloading dsp image...\n"); | |
179 | init_ft1000_netdev(ft1000dev); | |
180 | pft1000info = (FT1000_INFO *) netdev_priv (ft1000dev->net); | |
181 | ||
bf3146c8 | 182 | // DEBUG("In probe: pft1000info=%x\n", pft1000info); // aelias [-] reason: warning: format ???%x??? expects type ???unsigned int???, but argument 2 has type ???struct FT1000_INFO *??? |
7cfd8a37 | 183 | DEBUG("In probe: pft1000info=%p\n", pft1000info); // aelias [+] reason: up |
bf3146c8 | 184 | |
f7c1be0c MB |
185 | dsp_reload(ft1000dev); |
186 | gPollingfailed = FALSE; //mbelian | |
187 | pft1000info->pPollThread = kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll"); | |
188 | msleep(500); //mbelian | |
bf3146c8 GKH |
189 | |
190 | ||
f7c1be0c MB |
191 | if ( pft1000info->DSP_loading ) |
192 | { | |
193 | DEBUG("ERROR!!!! RETURN FROM ft1000_probe **********************\n"); | |
194 | return 0; | |
195 | } | |
bf3146c8 | 196 | |
f7c1be0c MB |
197 | while (!pft1000info->CardReady) |
198 | { | |
199 | if ( gPollingfailed ) | |
200 | { | |
201 | if ( pft1000info->pPollThread ) | |
202 | { | |
203 | kthread_stop(pft1000info->pPollThread ); | |
204 | } | |
205 | return 0; | |
206 | } | |
207 | msleep(100); | |
208 | DEBUG("ft1000_probe::Waiting for Card Ready\n"); | |
209 | } | |
bf3146c8 GKH |
210 | |
211 | ||
f7c1be0c MB |
212 | //initialize network device |
213 | DEBUG("ft1000_probe::Card Ready!!!! Registering network device\n"); | |
214 | ||
215 | reg_ft1000_netdev(ft1000dev, interface); | |
bf3146c8 | 216 | |
f7c1be0c MB |
217 | pft1000info->NetDevRegDone = 1; |
218 | ||
bf3146c8 | 219 | ft1000InitProc(ft1000dev->net);// +mbelian |
f7c1be0c MB |
220 | |
221 | return 0; | |
ada541f0 MB |
222 | |
223 | err_fw: | |
224 | kfree(ft1000dev); | |
225 | return ret; | |
f7c1be0c MB |
226 | } |
227 | ||
228 | //--------------------------------------------------------------------------- | |
229 | // Function: ft1000_disconnect | |
230 | // | |
231 | // Parameters: struct usb_interface *interface - passed by USB core | |
bf3146c8 | 232 | // |
f7c1be0c MB |
233 | // Returns: 0 - success |
234 | // | |
235 | // Description: This function is invoked when the express card is plugged out | |
236 | // | |
237 | // Notes: | |
238 | // | |
239 | //--------------------------------------------------------------------------- | |
240 | static void ft1000_disconnect(struct usb_interface *interface) | |
241 | { | |
242 | FT1000_INFO *pft1000info; | |
bf3146c8 | 243 | |
f7c1be0c | 244 | DEBUG("ft1000_disconnect is called\n"); |
bf3146c8 | 245 | |
f7c1be0c | 246 | pft1000info = (PFT1000_INFO)usb_get_intfdata(interface); |
bf3146c8 | 247 | // DEBUG("In disconnect pft1000info=%x\n", pft1000info); // aelias [-] reason: warning: format ???%x??? expects type ???unsigned int???, but argument 2 has type ???struct FT1000_INFO *??? |
7cfd8a37 | 248 | DEBUG("In disconnect pft1000info=%p\n", pft1000info); // aelias [+] reason: up |
f7c1be0c MB |
249 | |
250 | ||
251 | ||
252 | if (pft1000info) | |
253 | { | |
254 | ft1000CleanupProc(pft1000info); //+mbelian | |
255 | if ( pft1000info->pPollThread ) | |
256 | { | |
257 | kthread_stop(pft1000info->pPollThread ); | |
258 | } | |
bf3146c8 | 259 | |
f7c1be0c | 260 | DEBUG("ft1000_disconnect: threads are terminated\n"); |
bf3146c8 | 261 | |
f7c1be0c MB |
262 | if (pft1000info->pFt1000Dev->net) |
263 | { | |
264 | DEBUG("ft1000_disconnect: destroy char driver\n"); | |
265 | ft1000_DestroyDevice(pft1000info->pFt1000Dev->net); | |
266 | //DEBUG("ft1000_disconnect: calling ft1000_close\n"); | |
267 | //ft1000_close(pft1000info->pFt1000Dev->net); | |
268 | //DEBUG("ft1000_disconnect: ft1000_close is called\n"); | |
269 | unregister_netdev(pft1000info->pFt1000Dev->net); | |
270 | DEBUG("ft1000_disconnect: network device unregisterd\n"); | |
271 | free_netdev(pft1000info->pFt1000Dev->net); | |
272 | ||
273 | } | |
bf3146c8 | 274 | |
f7c1be0c MB |
275 | usb_free_urb(pft1000info->pFt1000Dev->rx_urb); |
276 | usb_free_urb(pft1000info->pFt1000Dev->tx_urb); | |
bf3146c8 | 277 | |
f7c1be0c MB |
278 | DEBUG("ft1000_disconnect: urb freed\n"); |
279 | ||
280 | kfree(pft1000info->pFt1000Dev); //+mbelian | |
281 | } | |
ada541f0 | 282 | kfree(pFileStart); |
f7c1be0c | 283 | //terminate other kernel threads |
bf3146c8 | 284 | //in multiple instances case, first find the device |
f7c1be0c MB |
285 | //in the link list |
286 | /**if (pPollThread) | |
287 | { | |
288 | kthread_stop(pPollThread); | |
289 | DEBUG("Polling thread is killed \n"); | |
290 | }**/ | |
291 | ||
292 | return; | |
293 | } | |
294 | ||
295 | static struct usb_driver ft1000_usb_driver = { | |
296 | //.owner = THIS_MODULE, | |
297 | .name = "ft1000usb", | |
298 | .probe = ft1000_probe, | |
299 | .disconnect = ft1000_disconnect, | |
300 | .id_table = id_table, | |
301 | }; | |
302 | ||
303 | //--------------------------------------------------------------------------- | |
304 | // Function: usb_ft1000_init | |
305 | // | |
306 | // Parameters: none | |
bf3146c8 | 307 | // |
f7c1be0c MB |
308 | // Returns: 0 - success |
309 | // | |
310 | // Description: The entry point of the module, register the usb driver | |
311 | // | |
312 | // Notes: | |
313 | // | |
314 | //--------------------------------------------------------------------------- | |
315 | static int __init usb_ft1000_init(void) | |
316 | { | |
317 | int ret = 0; | |
bf3146c8 | 318 | |
f7c1be0c MB |
319 | DEBUG("Initialize and register the driver\n"); |
320 | ||
321 | ret = usb_register(&ft1000_usb_driver); | |
322 | if (ret) | |
323 | err("usb_register failed. Error number %d", ret); | |
324 | ||
325 | return ret; | |
326 | } | |
327 | ||
328 | //--------------------------------------------------------------------------- | |
329 | // Function: usb_ft1000_exit | |
330 | // | |
bf3146c8 GKH |
331 | // Parameters: |
332 | // | |
333 | // Returns: | |
f7c1be0c MB |
334 | // |
335 | // Description: Moudle unload function, deregister usb driver | |
336 | // | |
337 | // Notes: | |
338 | // | |
339 | //--------------------------------------------------------------------------- | |
340 | static void __exit usb_ft1000_exit(void) | |
341 | { | |
342 | DEBUG("Deregister the driver\n"); | |
343 | usb_deregister(&ft1000_usb_driver); | |
344 | } | |
345 | ||
346 | module_init (usb_ft1000_init); | |
347 | module_exit (usb_ft1000_exit); | |
348 | ||
349 |