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/kernel.h> |
11 | #include <linux/module.h> | |
12 | #include <linux/usb.h> | |
13 | #include <linux/netdevice.h> | |
14 | #include <linux/etherdevice.h> | |
ada541f0 | 15 | #include <linux/firmware.h> |
f7c1be0c MB |
16 | #include "ft1000_usb.h" |
17 | ||
f7c1be0c MB |
18 | #include <linux/kthread.h> |
19 | ||
20 | MODULE_DESCRIPTION("FT1000 EXPRESS CARD DRIVER"); | |
21 | MODULE_LICENSE("Dual MPL/GPL"); | |
22 | MODULE_SUPPORTED_DEVICE("QFT FT1000 Express Cards"); | |
23 | ||
f7c1be0c | 24 | void *pFileStart; |
2a953cfd | 25 | size_t FileLength; |
f7c1be0c | 26 | |
47873d33 MB |
27 | #define VENDOR_ID 0x1291 /* Qualcomm vendor id */ |
28 | #define PRODUCT_ID 0x11 /* fake product id */ | |
f7c1be0c MB |
29 | |
30 | /* table of devices that work with this driver */ | |
31 | static struct usb_device_id id_table[] = { | |
47873d33 MB |
32 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, |
33 | {}, | |
f7c1be0c MB |
34 | }; |
35 | ||
0f570d8c | 36 | MODULE_DEVICE_TABLE(usb, id_table); |
f7c1be0c | 37 | |
dfff0c3f | 38 | static bool gPollingfailed = false; |
3bc2311e | 39 | static int ft1000_poll_thread(void *arg) |
f7c1be0c | 40 | { |
b7c5a774 | 41 | int ret; |
47873d33 MB |
42 | |
43 | while (!kthread_should_stop()) { | |
44 | msleep(10); | |
45 | if (!gPollingfailed) { | |
46 | ret = ft1000_poll(arg); | |
46d98155 | 47 | if (ret != 0) { |
47873d33 | 48 | DEBUG("ft1000_poll_thread: polling failed\n"); |
dfff0c3f | 49 | gPollingfailed = true; |
47873d33 MB |
50 | } |
51 | } | |
52 | } | |
46d98155 | 53 | return 0; |
f7c1be0c MB |
54 | } |
55 | ||
c6f2c47b MB |
56 | static int ft1000_probe(struct usb_interface *interface, |
57 | const struct usb_device_id *id) | |
f7c1be0c | 58 | { |
47873d33 MB |
59 | struct usb_host_interface *iface_desc; |
60 | struct usb_endpoint_descriptor *endpoint; | |
61 | struct usb_device *dev; | |
62 | unsigned numaltsetting; | |
ada541f0 | 63 | int i, ret = 0, size; |
f7c1be0c | 64 | |
dedbc933 | 65 | struct ft1000_usb *ft1000dev; |
7716090b | 66 | struct ft1000_info *pft1000info = NULL; |
ada541f0 MB |
67 | const struct firmware *dsp_fw; |
68 | ||
dedbc933 | 69 | ft1000dev = kzalloc(sizeof(struct ft1000_usb), GFP_KERNEL); |
78110bb8 | 70 | if (!ft1000dev) |
b10c0b92 | 71 | return -ENOMEM; |
f7c1be0c | 72 | |
47873d33 MB |
73 | dev = interface_to_usbdev(interface); |
74 | DEBUG("ft1000_probe: usb device descriptor info:\n"); | |
c6f2c47b MB |
75 | DEBUG("ft1000_probe: number of configuration is %d\n", |
76 | dev->descriptor.bNumConfigurations); | |
f7c1be0c MB |
77 | |
78 | ft1000dev->dev = dev; | |
79 | ft1000dev->status = 0; | |
80 | ft1000dev->net = NULL; | |
773fe724 AK |
81 | ft1000dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); |
82 | ft1000dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
83 | if (!ft1000dev->tx_urb || !ft1000dev->rx_urb) { | |
84 | ret = -ENOMEM; | |
85 | goto err_fw; | |
86 | } | |
f7c1be0c | 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 | ||
dfff0c3f | 173 | gPollingfailed = false; |
3aa2303a | 174 | ft1000dev->pPollThread = |
c6f2c47b | 175 | kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll"); |
c8b124e2 | 176 | |
3aa2303a OZ |
177 | if (IS_ERR(ft1000dev->pPollThread)) { |
178 | ret = PTR_ERR(ft1000dev->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 | |
3aa2303a | 203 | ft1000dev->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: |
3aa2303a | 211 | kthread_stop(ft1000dev->pPollThread); |
4960b8fe | 212 | err_load: |
5cb9954a | 213 | kfree(pFileStart); |
ada541f0 | 214 | err_fw: |
773fe724 AK |
215 | usb_free_urb(ft1000dev->rx_urb); |
216 | usb_free_urb(ft1000dev->tx_urb); | |
ada541f0 MB |
217 | kfree(ft1000dev); |
218 | return ret; | |
f7c1be0c MB |
219 | } |
220 | ||
f7c1be0c MB |
221 | static void ft1000_disconnect(struct usb_interface *interface) |
222 | { | |
1a88a068 | 223 | struct ft1000_info *pft1000info; |
dedbc933 | 224 | struct ft1000_usb *ft1000dev; |
bf3146c8 | 225 | |
47873d33 | 226 | DEBUG("ft1000_disconnect is called\n"); |
bf3146c8 | 227 | |
1a88a068 | 228 | pft1000info = (struct ft1000_info *) usb_get_intfdata(interface); |
4aee92f6 | 229 | DEBUG("In disconnect pft1000info=%p\n", pft1000info); |
f7c1be0c | 230 | |
47873d33 | 231 | if (pft1000info) { |
3aa2303a | 232 | ft1000dev = pft1000info->priv; |
dab56ffe | 233 | ft1000_cleanup_proc(pft1000info); |
3aa2303a OZ |
234 | if (ft1000dev->pPollThread) |
235 | kthread_stop(ft1000dev->pPollThread); | |
bf3146c8 | 236 | |
47873d33 | 237 | DEBUG("ft1000_disconnect: threads are terminated\n"); |
bf3146c8 | 238 | |
3aa2303a | 239 | if (ft1000dev->net) { |
47873d33 | 240 | DEBUG("ft1000_disconnect: destroy char driver\n"); |
3aa2303a OZ |
241 | ft1000_destroy_dev(ft1000dev->net); |
242 | unregister_netdev(ft1000dev->net); | |
47873d33 | 243 | DEBUG |
aaf3ee4f | 244 | ("ft1000_disconnect: network device unregistered\n"); |
3aa2303a | 245 | free_netdev(ft1000dev->net); |
f7c1be0c | 246 | |
47873d33 | 247 | } |
bf3146c8 | 248 | |
3aa2303a OZ |
249 | usb_free_urb(ft1000dev->rx_urb); |
250 | usb_free_urb(ft1000dev->tx_urb); | |
bf3146c8 | 251 | |
47873d33 | 252 | DEBUG("ft1000_disconnect: urb freed\n"); |
f7c1be0c | 253 | |
3aa2303a | 254 | kfree(ft1000dev); |
47873d33 | 255 | } |
ada541f0 | 256 | kfree(pFileStart); |
f7c1be0c | 257 | |
47873d33 | 258 | return; |
f7c1be0c MB |
259 | } |
260 | ||
261 | static struct usb_driver ft1000_usb_driver = { | |
47873d33 MB |
262 | .name = "ft1000usb", |
263 | .probe = ft1000_probe, | |
264 | .disconnect = ft1000_disconnect, | |
265 | .id_table = id_table, | |
f7c1be0c MB |
266 | }; |
267 | ||
bac2c126 | 268 | module_usb_driver(ft1000_usb_driver); |