| 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 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 urb = client_delurb(dev, cid); | 729 urb = client_delurb(dev, cid); |
| 730 } | 730 } |
| 731 | 731 |
| 732 while (client_delread(dev, cid, 0, &data, &size)) | 732 while (client_delread(dev, cid, 0, &data, &size)) |
| 733 kfree(data); | 733 kfree(data); |
| 734 | 734 |
| 735 list_del(&client->node); | 735 list_del(&client->node); |
| 736 kfree(client); | 736 kfree(client); |
| 737 } | 737 } |
| 738 } | 738 } |
| 739 | |
| 740 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); | 739 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); |
| 741 } | 740 } |
| 742 | 741 |
| 743 struct client *client_bycid(struct qcusbnet *dev, u16 cid) | 742 struct client *client_bycid(struct qcusbnet *dev, u16 cid) |
| 744 { | 743 { |
| 745 struct list_head *node; | 744 struct list_head *node; |
| 746 struct client *client; | 745 struct client *client; |
| 747 | 746 |
| 748 if (!device_valid(dev)) { | 747 if (!device_valid(dev)) { |
| 749 DBG("Invalid device\n"); | 748 DBG("Invalid device\n"); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 kfree(req); | 942 kfree(req); |
| 944 return urb; | 943 return urb; |
| 945 } | 944 } |
| 946 | 945 |
| 947 static int devqmi_open(struct inode *inode, struct file *file) | 946 static int devqmi_open(struct inode *inode, struct file *file) |
| 948 { | 947 { |
| 949 struct qmihandle *handle; | 948 struct qmihandle *handle; |
| 950 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev)
; | 949 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev)
; |
| 951 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi); | 950 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi); |
| 952 | 951 |
| 953 » if (!device_valid(dev)) { | 952 » /* We need an extra ref on the device per fd, since we stash a pointer |
| 954 » » DBG("Invalid device\n"); | 953 » * in the handle structure. */ |
| 954 » struct qcusbnet *ref = qcusbnet_get(dev); |
| 955 |
| 956 » if (!ref) |
| 955 return -ENXIO; | 957 return -ENXIO; |
| 956 } | |
| 957 | 958 |
| 958 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); | 959 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); |
| 959 if (!file->private_data) { | 960 if (!file->private_data) { |
| 960 DBG("Mem error\n"); | 961 DBG("Mem error\n"); |
| 961 return -ENOMEM; | 962 return -ENOMEM; |
| 962 } | 963 } |
| 963 | 964 |
| 964 handle = (struct qmihandle *)file->private_data; | 965 handle = (struct qmihandle *)file->private_data; |
| 965 handle->cid = (u16)-1; | 966 handle->cid = (u16)-1; |
| 966 » handle->dev = dev; | 967 » handle->dev = ref; |
| 967 | 968 |
| 968 DBG("%p %04x", handle, handle->cid); | 969 DBG("%p %04x", handle, handle->cid); |
| 969 | 970 |
| 970 return 0; | 971 return 0; |
| 971 } | 972 } |
| 972 | 973 |
| 973 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
, unsigned long arg) | 974 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd
, unsigned long arg) |
| 974 { | 975 { |
| 975 int result; | 976 int result; |
| 976 u32 vidpid; | 977 u32 vidpid; |
| 977 | 978 |
| 978 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 979 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
| 979 | 980 |
| 980 DBG("%p %04x %08x", handle, handle->cid, cmd); | 981 DBG("%p %04x %08x", handle, handle->cid, cmd); |
| 981 | 982 |
| 982 if (!handle) { | 983 if (!handle) { |
| 983 DBG("Bad file data\n"); | 984 DBG("Bad file data\n"); |
| 984 return -EBADF; | 985 return -EBADF; |
| 985 } | 986 } |
| 986 | 987 |
| 988 if (handle->dev->dying) { |
| 989 DBG("Dying device"); |
| 990 return -ENXIO; |
| 991 } |
| 992 |
| 987 if (!device_valid(handle->dev)) { | 993 if (!device_valid(handle->dev)) { |
| 988 DBG("Invalid device! Updating f_ops\n"); | 994 DBG("Invalid device! Updating f_ops\n"); |
| 989 file->f_op = file->f_dentry->d_inode->i_fop; | 995 file->f_op = file->f_dentry->d_inode->i_fop; |
| 990 return -ENXIO; | 996 return -ENXIO; |
| 991 } | 997 } |
| 992 | 998 |
| 993 switch (cmd) { | 999 switch (cmd) { |
| 994 case IOCTL_QMI_GET_SERVICE_FILE: | 1000 case IOCTL_QMI_GET_SERVICE_FILE: |
| 995 | 1001 |
| 996 DBG("Setting up QMI for service %lu\n", arg); | 1002 DBG("Setting up QMI for service %lu\n", arg); |
| 997 if (!(u8)arg) { | 1003 if (!(u8)arg) { |
| 998 DBG("Cannot use QMICTL from userspace\n"); | 1004 DBG("Cannot use QMICTL from userspace\n"); |
| 999 return -EINVAL; | 1005 return -EINVAL; |
| 1000 } | 1006 } |
| 1001 | 1007 |
| 1002 if (handle->cid != (u16)-1) { | 1008 if (handle->cid != (u16)-1) { |
| 1003 DBG("Close the current connection before opening a new o
ne\n"); | 1009 DBG("Close the current connection before opening a new o
ne\n"); |
| 1004 return -EBADR; | 1010 return -EBADR; |
| 1005 } | 1011 } |
| 1006 | 1012 |
| 1007 result = client_alloc(handle->dev, (u8)arg); | 1013 result = client_alloc(handle->dev, (u8)arg); |
| 1008 if (result < 0) | 1014 if (result < 0) |
| 1009 return result; | 1015 return result; |
| 1010 handle->cid = result; | 1016 handle->cid = result; |
| 1011 | 1017 |
| 1012 return 0; | 1018 return 0; |
| 1013 break; | 1019 break; |
| 1014 | 1020 |
| 1015 | |
| 1016 case IOCTL_QMI_GET_DEVICE_VIDPID: | 1021 case IOCTL_QMI_GET_DEVICE_VIDPID: |
| 1017 if (!arg) { | 1022 if (!arg) { |
| 1018 DBG("Bad VIDPID buffer\n"); | 1023 DBG("Bad VIDPID buffer\n"); |
| 1019 return -EINVAL; | 1024 return -EINVAL; |
| 1020 } | 1025 } |
| 1021 | 1026 |
| 1022 if (!handle->dev->usbnet) { | 1027 if (!handle->dev->usbnet) { |
| 1023 DBG("Bad usbnet\n"); | 1028 DBG("Bad usbnet\n"); |
| 1024 return -ENOMEM; | 1029 return -ENOMEM; |
| 1025 } | 1030 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1120 int result; | 1125 int result; |
| 1121 void *data = NULL; | 1126 void *data = NULL; |
| 1122 void *smalldata; | 1127 void *smalldata; |
| 1123 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1128 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
| 1124 | 1129 |
| 1125 if (!handle) { | 1130 if (!handle) { |
| 1126 DBG("Bad file data\n"); | 1131 DBG("Bad file data\n"); |
| 1127 return -EBADF; | 1132 return -EBADF; |
| 1128 } | 1133 } |
| 1129 | 1134 |
| 1135 if (handle->dev->dying) { |
| 1136 DBG("Dying device"); |
| 1137 return -ENXIO; |
| 1138 } |
| 1139 |
| 1130 if (!device_valid(handle->dev)) { | 1140 if (!device_valid(handle->dev)) { |
| 1131 DBG("Invalid device! Updating f_ops\n"); | 1141 DBG("Invalid device! Updating f_ops\n"); |
| 1132 file->f_op = file->f_dentry->d_inode->i_fop; | 1142 file->f_op = file->f_dentry->d_inode->i_fop; |
| 1133 return -ENXIO; | 1143 return -ENXIO; |
| 1134 } | 1144 } |
| 1135 | 1145 |
| 1136 if (handle->cid == (u16)-1) { | 1146 if (handle->cid == (u16)-1) { |
| 1137 DBG("Client ID must be set before reading 0x%04X\n", | 1147 DBG("Client ID must be set before reading 0x%04X\n", |
| 1138 handle->cid); | 1148 handle->cid); |
| 1139 return -EBADR; | 1149 return -EBADR; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1205 } | 1215 } |
| 1206 | 1216 |
| 1207 int qc_register(struct qcusbnet *dev) | 1217 int qc_register(struct qcusbnet *dev) |
| 1208 { | 1218 { |
| 1209 int result; | 1219 int result; |
| 1210 int qmiidx = 0; | 1220 int qmiidx = 0; |
| 1211 dev_t devno; | 1221 dev_t devno; |
| 1212 char *name; | 1222 char *name; |
| 1213 | 1223 |
| 1214 dev->valid = true; | 1224 dev->valid = true; |
| 1225 dev->dying = false; |
| 1215 result = client_alloc(dev, QMICTL); | 1226 result = client_alloc(dev, QMICTL); |
| 1216 if (result) { | 1227 if (result) { |
| 1217 dev->valid = false; | 1228 dev->valid = false; |
| 1218 return result; | 1229 return result; |
| 1219 } | 1230 } |
| 1220 atomic_set(&dev->qmi.qmitid, 1); | 1231 atomic_set(&dev->qmi.qmitid, 1); |
| 1221 | 1232 |
| 1222 result = qc_startread(dev); | 1233 result = qc_startread(dev); |
| 1223 if (result) { | 1234 if (result) { |
| 1224 dev->valid = false; | 1235 dev->valid = false; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1273 | 1284 |
| 1274 dev->qmi.devnum = devno; | 1285 dev->qmi.devnum = devno; |
| 1275 return 0; | 1286 return 0; |
| 1276 } | 1287 } |
| 1277 | 1288 |
| 1278 void qc_deregister(struct qcusbnet *dev) | 1289 void qc_deregister(struct qcusbnet *dev) |
| 1279 { | 1290 { |
| 1280 struct list_head *node, *tmp; | 1291 struct list_head *node, *tmp; |
| 1281 struct client *client; | 1292 struct client *client; |
| 1282 struct inode *inode; | 1293 struct inode *inode; |
| 1283 struct list_head *inodes; | |
| 1284 struct task_struct *task; | |
| 1285 struct fdtable *fdtable; | |
| 1286 struct file *file; | |
| 1287 unsigned long flags; | |
| 1288 int count = 0; | |
| 1289 | 1294 |
| 1290 if (!device_valid(dev)) { | 1295 if (!device_valid(dev)) { |
| 1291 DBG("wrong device\n"); | 1296 DBG("wrong device\n"); |
| 1292 return; | 1297 return; |
| 1293 } | 1298 } |
| 1294 | 1299 |
| 1295 list_for_each_safe(node, tmp, &dev->qmi.clients) { | 1300 list_for_each_safe(node, tmp, &dev->qmi.clients) { |
| 1296 client = list_entry(node, struct client, node); | 1301 client = list_entry(node, struct client, node); |
| 1297 DBG("release 0x%04X\n", client->cid); | 1302 DBG("release 0x%04X\n", client->cid); |
| 1298 client_free(dev, client->cid); | 1303 client_free(dev, client->cid); |
| 1299 } | 1304 } |
| 1300 | 1305 |
| 1301 qc_stopread(dev); | 1306 qc_stopread(dev); |
| 1302 dev->valid = false; | 1307 dev->valid = false; |
| 1303 list_for_each(inodes, &dev->qmi.cdev.list) { | |
| 1304 inode = container_of(inodes, struct inode, i_devices); | |
| 1305 if (inode != NULL && !IS_ERR(inode)) { | |
| 1306 rcu_read_lock(); | |
| 1307 for_each_process(task) { | |
| 1308 if (!task || !task->files) | |
| 1309 continue; | |
| 1310 spin_lock_irqsave(&task->files->file_lock, flags
); | |
| 1311 fdtable = files_fdtable(task->files); | |
| 1312 for (count = 0; count < fdtable->max_fds; count+
+) { | |
| 1313 file = fdtable->fd[count]; | |
| 1314 if (file != NULL && file->f_dentry != N
ULL) { | |
| 1315 if (file->f_dentry->d_inode == i
node) { | |
| 1316 rcu_assign_pointer(fdtab
le->fd[count], NULL); | |
| 1317 spin_unlock_irqrestore(&
task->files->file_lock, flags); | |
| 1318 DBG("forcing close of op
en file handle\n"); | |
| 1319 filp_close(file, task->f
iles); | |
| 1320 spin_lock_irqsave(&task-
>files->file_lock, flags); | |
| 1321 } | |
| 1322 } | |
| 1323 } | |
| 1324 spin_unlock_irqrestore(&task->files->file_lock,
flags); | |
| 1325 } | |
| 1326 rcu_read_unlock(); | |
| 1327 } | |
| 1328 } | |
| 1329 | |
| 1330 if (!IS_ERR(dev->qmi.devclass)) | 1308 if (!IS_ERR(dev->qmi.devclass)) |
| 1331 device_destroy(dev->qmi.devclass, dev->qmi.devnum); | 1309 device_destroy(dev->qmi.devclass, dev->qmi.devnum); |
| 1332 cdev_del(&dev->qmi.cdev); | 1310 cdev_del(&dev->qmi.cdev); |
| 1333 unregister_chrdev_region(dev->qmi.devnum, 1); | 1311 unregister_chrdev_region(dev->qmi.devnum, 1); |
| 1334 } | 1312 } |
| 1335 | 1313 |
| 1336 static bool qmi_ready(struct qcusbnet *dev, u16 timeout) | 1314 static bool qmi_ready(struct qcusbnet *dev, u16 timeout) |
| 1337 { | 1315 { |
| 1338 int result; | 1316 int result; |
| 1339 void *wbuf; | 1317 void *wbuf; |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 DBG("bad get MEID resp\n"); | 1561 DBG("bad get MEID resp\n"); |
| 1584 memset(&dev->meid[0], '0', 14); | 1562 memset(&dev->meid[0], '0', 14); |
| 1585 } | 1563 } |
| 1586 | 1564 |
| 1587 client_free(dev, cid); | 1565 client_free(dev, cid); |
| 1588 return 0; | 1566 return 0; |
| 1589 } | 1567 } |
| 1590 | 1568 |
| 1591 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); | 1569 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); |
| 1592 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); | 1570 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); |
| OLD | NEW |