| 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 |