OLD | NEW |
1 /* qmidevice.c - gobi QMI device | 1 /* qmidevice.c - gobi QMI device |
2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved. |
3 | 3 |
4 * This program is free software; you can redistribute it and/or modify | 4 * This program is free software; you can redistribute it and/or modify |
5 * it under the terms of the GNU General Public License version 2 and | 5 * it under the terms of the GNU General Public License version 2 and |
6 * only version 2 as published by the Free Software Foundation. | 6 * only version 2 as published by the Free Software Foundation. |
7 | 7 |
8 * This program is distributed in the hope that it will be useful, | 8 * This program is distributed in the hope that it will be useful, |
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 static struct client *client_bycid(struct qcusbnet *dev, u16 cid); | 61 static struct client *client_bycid(struct qcusbnet *dev, u16 cid); |
62 static bool client_addread(struct qcusbnet *dev, u16 cid, u16 tid, void *data, u
16 size); | 62 static bool client_addread(struct qcusbnet *dev, u16 cid, u16 tid, void *data, u
16 size); |
63 static bool client_delread(struct qcusbnet *dev, u16 cid, u16 tid, void **data,
u16 *size); | 63 static bool client_delread(struct qcusbnet *dev, u16 cid, u16 tid, void **data,
u16 *size); |
64 static bool client_addnotify(struct qcusbnet *dev, u16 cid, u16 tid, | 64 static bool client_addnotify(struct qcusbnet *dev, u16 cid, u16 tid, |
65 void (*hook)(struct qcusbnet *, u16 cid, void *), | 65 void (*hook)(struct qcusbnet *, u16 cid, void *), |
66 void *data); | 66 void *data); |
67 static bool client_notify(struct qcusbnet *dev, u16 cid, u16 tid); | 67 static bool client_notify(struct qcusbnet *dev, u16 cid, u16 tid); |
68 static bool client_addurb(struct qcusbnet *dev, u16 cid, struct urb *urb); | 68 static bool client_addurb(struct qcusbnet *dev, u16 cid, struct urb *urb); |
69 static struct urb *client_delurb(struct qcusbnet *dev, u16 cid); | 69 static struct urb *client_delurb(struct qcusbnet *dev, u16 cid); |
70 | 70 |
| 71 static int resubmit_int_urb(struct urb *urb); |
| 72 |
71 static int devqmi_open(struct inode *inode, struct file *file); | 73 static int devqmi_open(struct inode *inode, struct file *file); |
72 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
, unsigned long arg); | 74 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
, unsigned long arg); |
73 static int devqmi_release(struct inode *inode, struct file *file); | 75 static int devqmi_release(struct inode *inode, struct file *file); |
74 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, | 76 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, |
75 loff_t *pos); | 77 loff_t *pos); |
76 static ssize_t devqmi_write(struct file *file, const char __user *buf, | 78 static ssize_t devqmi_write(struct file *file, const char __user *buf, |
77 size_t size, loff_t *pos); | 79 size_t size, loff_t *pos); |
78 | 80 |
79 static bool qmi_ready(struct qcusbnet *dev, u16 timeout); | 81 static bool qmi_ready(struct qcusbnet *dev, u16 timeout); |
80 static void wds_callback(struct qcusbnet *dev, u16 cid, void *data); | 82 static void wds_callback(struct qcusbnet *dev, u16 cid, void *data); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 clear_bit(reason, &dev->down); | 127 clear_bit(reason, &dev->down); |
126 if (!dev->down) | 128 if (!dev->down) |
127 netif_carrier_on(dev->usbnet->net); | 129 netif_carrier_on(dev->usbnet->net); |
128 } | 130 } |
129 | 131 |
130 bool qc_isdown(struct qcusbnet *dev, u8 reason) | 132 bool qc_isdown(struct qcusbnet *dev, u8 reason) |
131 { | 133 { |
132 return test_bit(reason, &dev->down); | 134 return test_bit(reason, &dev->down); |
133 } | 135 } |
134 | 136 |
| 137 static int resubmit_int_urb(struct urb *urb) |
| 138 { |
| 139 int status; |
| 140 int interval; |
| 141 if (!urb || !urb->dev) |
| 142 return -EINVAL; |
| 143 interval = urb->dev->speed == USB_SPEED_HIGH ? 7 : 3; |
| 144 usb_fill_int_urb(urb, urb->dev, urb->pipe, urb->transfer_buffer, |
| 145 urb->transfer_buffer_length, urb->complete, |
| 146 urb->context, interval); |
| 147 status = usb_submit_urb(urb, GFP_ATOMIC); |
| 148 if (status) |
| 149 DBG("status %d", status); |
| 150 return status; |
| 151 } |
| 152 |
135 static void read_callback(struct urb *urb) | 153 static void read_callback(struct urb *urb) |
136 { | 154 { |
137 struct list_head *node; | 155 struct list_head *node; |
138 int result; | 156 int result; |
139 u16 cid; | 157 u16 cid; |
140 struct client *client; | 158 struct client *client; |
141 void *data; | 159 void *data; |
142 void *copy; | 160 void *copy; |
143 u16 size; | 161 u16 size; |
144 struct qcusbnet *dev; | 162 struct qcusbnet *dev; |
145 unsigned long flags; | 163 unsigned long flags; |
146 u16 tid; | 164 u16 tid; |
147 | 165 |
148 if (!urb) { | 166 if (!urb) { |
149 DBG("bad read URB\n"); | 167 DBG("bad read URB\n"); |
150 return; | 168 return; |
151 } | 169 } |
152 | 170 |
153 dev = urb->context; | 171 dev = urb->context; |
154 if (!device_valid(dev)) { | 172 if (!device_valid(dev)) { |
155 DBG("Invalid device!\n"); | 173 DBG("Invalid device!\n"); |
156 return; | 174 return; |
157 } | 175 } |
158 | 176 |
159 if (urb->status) { | 177 if (urb->status) { |
160 DBG("Read status = %d\n", urb->status); | 178 DBG("Read status = %d\n", urb->status); |
| 179 resubmit_int_urb(dev->qmi.inturb); |
161 return; | 180 return; |
162 } | 181 } |
163 | 182 |
164 DBG("Read %d bytes\n", urb->actual_length); | 183 DBG("Read %d bytes\n", urb->actual_length); |
165 | 184 |
166 data = urb->transfer_buffer; | 185 data = urb->transfer_buffer; |
167 size = urb->actual_length; | 186 size = urb->actual_length; |
168 | 187 |
169 if (qcusbnet_debug) | 188 if (qcusbnet_debug) |
170 print_hex_dump(KERN_INFO, "gobi-read: ", DUMP_PREFIX_OFFSET, | 189 print_hex_dump(KERN_INFO, "gobi-read: ", DUMP_PREFIX_OFFSET, |
171 16, 1, data, size, true); | 190 16, 1, data, size, true); |
172 | 191 |
173 result = qmux_parse(&cid, data, size); | 192 result = qmux_parse(&cid, data, size); |
174 if (result < 0) { | 193 if (result < 0) { |
175 DBG("Read error parsing QMUX %d\n", result); | 194 DBG("Read error parsing QMUX %d\n", result); |
| 195 resubmit_int_urb(dev->qmi.inturb); |
176 return; | 196 return; |
177 } | 197 } |
178 | 198 |
179 if (size < result + 3) { | 199 if (size < result + 3) { |
180 DBG("Data buffer too small to parse\n"); | 200 DBG("Data buffer too small to parse\n"); |
| 201 resubmit_int_urb(dev->qmi.inturb); |
181 return; | 202 return; |
182 } | 203 } |
183 | 204 |
184 if (cid == QMICTL) | 205 if (cid == QMICTL) |
185 tid = *(u8 *)(data + result + 1); | 206 tid = *(u8 *)(data + result + 1); |
186 else | 207 else |
187 tid = *(u16 *)(data + result + 1); | 208 tid = *(u16 *)(data + result + 1); |
188 spin_lock_irqsave(&dev->qmi.clients_lock, flags); | 209 spin_lock_irqsave(&dev->qmi.clients_lock, flags); |
189 | 210 |
190 list_for_each(node, &dev->qmi.clients) { | 211 list_for_each(node, &dev->qmi.clients) { |
191 client = list_entry(node, struct client, node); | 212 client = list_entry(node, struct client, node); |
192 if (client->cid == cid || (client->cid | 0xff00) == cid) { | 213 if (client->cid == cid || (client->cid | 0xff00) == cid) { |
193 copy = kmalloc(size, GFP_ATOMIC); | 214 copy = kmalloc(size, GFP_ATOMIC); |
194 memcpy(copy, data, size); | 215 memcpy(copy, data, size); |
195 if (!client_addread(dev, client->cid, tid, copy, size))
{ | 216 if (!client_addread(dev, client->cid, tid, copy, size))
{ |
196 DBG("Error allocating pReadMemListEntry " | 217 DBG("Error allocating pReadMemListEntry " |
197 "read will be discarded\n"); | 218 "read will be discarded\n"); |
198 kfree(copy); | 219 kfree(copy); |
199 spin_unlock_irqrestore(&dev->qmi.clients_lock, f
lags); | 220 spin_unlock_irqrestore(&dev->qmi.clients_lock, f
lags); |
| 221 resubmit_int_urb(dev->qmi.inturb); |
200 return; | 222 return; |
201 } | 223 } |
202 | 224 |
203 DBG("Creating new readListEntry for client 0x%04X, TID %
x\n", | 225 DBG("Creating new readListEntry for client 0x%04X, TID %
x\n", |
204 cid, tid); | 226 cid, tid); |
205 | 227 |
206 client_notify(dev, client->cid, tid); | 228 client_notify(dev, client->cid, tid); |
207 | 229 |
208 if (cid >> 8 != 0xff) | 230 if (cid >> 8 != 0xff) |
209 break; | 231 break; |
210 } | 232 } |
211 } | 233 } |
212 | 234 |
213 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); | 235 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); |
| 236 resubmit_int_urb(dev->qmi.inturb); |
214 } | 237 } |
215 | 238 |
216 static void int_callback(struct urb *urb) | 239 static void int_callback(struct urb *urb) |
217 { | 240 { |
218 int status; | 241 int status; |
219 int interval; | 242 int interval; |
220 struct qcusbnet *dev = (struct qcusbnet *)urb->context; | 243 struct qcusbnet *dev = (struct qcusbnet *)urb->context; |
221 | 244 |
222 if (!device_valid(dev)) { | 245 if (!device_valid(dev)) { |
223 DBG("Invalid device!\n"); | 246 DBG("Invalid device!\n"); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 } else { | 280 } else { |
258 DBG("ignoring invalid interrupt in packet\n"); | 281 DBG("ignoring invalid interrupt in packet\n"); |
259 if (qcusbnet_debug) | 282 if (qcusbnet_debug) |
260 print_hex_dump(KERN_INFO, "gobi-int: ", | 283 print_hex_dump(KERN_INFO, "gobi-int: ", |
261 DUMP_PREFIX_OFFSET, 16, 1, | 284 DUMP_PREFIX_OFFSET, 16, 1, |
262 urb->transfer_buffer, | 285 urb->transfer_buffer, |
263 urb->actual_length, true); | 286 urb->actual_length, true); |
264 } | 287 } |
265 } | 288 } |
266 | 289 |
267 » interval = (dev->usbnet->udev->speed == USB_SPEED_HIGH) ? 7 : 3; | 290 » resubmit_int_urb(dev->qmi.inturb); |
268 | |
269 » usb_fill_int_urb(urb, urb->dev,»urb->pipe, urb->transfer_buffer, | |
270 » » » urb->transfer_buffer_length, urb->complete, | |
271 » » » urb->context, interval); | |
272 » status = usb_submit_urb(urb, GFP_ATOMIC); | |
273 » if (status) | |
274 » » DBG("Error re-submitting Int URB %d\n", status); | |
275 return; | 291 return; |
276 } | 292 } |
277 | 293 |
278 int qc_startread(struct qcusbnet *dev) | 294 int qc_startread(struct qcusbnet *dev) |
279 { | 295 { |
280 int interval; | 296 int interval; |
281 | 297 |
282 if (!device_valid(dev)) { | 298 if (!device_valid(dev)) { |
283 DBG("Invalid device!\n"); | 299 DBG("Invalid device!\n"); |
284 return -ENXIO; | 300 return -ENXIO; |
(...skipping 1252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1537 DBG("bad get MEID resp\n"); | 1553 DBG("bad get MEID resp\n"); |
1538 memset(&dev->meid[0], '0', 14); | 1554 memset(&dev->meid[0], '0', 14); |
1539 } | 1555 } |
1540 | 1556 |
1541 client_free(dev, cid); | 1557 client_free(dev, cid); |
1542 return 0; | 1558 return 0; |
1543 } | 1559 } |
1544 | 1560 |
1545 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); | 1561 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); |
1546 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); | 1562 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); |
OLD | NEW |