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 ref |
954 » » DBG("Invalid device\n"); | 953 » * inside the handle. If qcusbnet_get() returns NULL, that means the |
954 » * device has been removed from the list - no new refs for us. */ | |
955 » struct qcusbnet *ref = qcusbnet_get(dev); | |
956 | |
957 » if (!ref) | |
955 return -ENXIO; | 958 return -ENXIO; |
956 } | |
957 | 959 |
958 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); | 960 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); |
959 if (!file->private_data) { | 961 if (!file->private_data) { |
960 DBG("Mem error\n"); | 962 DBG("Mem error\n"); |
961 return -ENOMEM; | 963 return -ENOMEM; |
962 } | 964 } |
963 | 965 |
964 handle = (struct qmihandle *)file->private_data; | 966 handle = (struct qmihandle *)file->private_data; |
965 handle->cid = (u16)-1; | 967 handle->cid = (u16)-1; |
966 » handle->dev = dev; | 968 » handle->dev = ref; |
967 | 969 |
968 DBG("%p %04x", handle, handle->cid); | 970 DBG("%p %04x", handle, handle->cid); |
969 | 971 |
970 return 0; | 972 return 0; |
971 } | 973 } |
972 | 974 |
973 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg) | 975 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg) |
974 { | 976 { |
975 int result; | 977 int result; |
976 u32 vidpid; | 978 u32 vidpid; |
977 | 979 |
978 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 980 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
979 | 981 |
980 DBG("%p %04x %08x", handle, handle->cid, cmd); | 982 DBG("%p %04x %08x", handle, handle->cid, cmd); |
981 | 983 |
982 if (!handle) { | 984 if (!handle) { |
983 DBG("Bad file data\n"); | 985 DBG("Bad file data\n"); |
984 return -EBADF; | 986 return -EBADF; |
985 } | 987 } |
986 | 988 |
989 if (handle->dev->dying) { | |
Jason Glasgow
2011/03/10 18:36:28
Dying never set to true.
Elly Fong-Jones
2011/03/10 19:15:46
Oops. Supposed to be done early in qc_deregister()
| |
990 DBG("Dying device"); | |
991 return -ENXIO; | |
992 } | |
993 | |
987 if (!device_valid(handle->dev)) { | 994 if (!device_valid(handle->dev)) { |
988 DBG("Invalid device! Updating f_ops\n"); | 995 DBG("Invalid device! Updating f_ops\n"); |
989 file->f_op = file->f_dentry->d_inode->i_fop; | 996 file->f_op = file->f_dentry->d_inode->i_fop; |
990 return -ENXIO; | 997 return -ENXIO; |
991 } | 998 } |
992 | 999 |
993 switch (cmd) { | 1000 switch (cmd) { |
994 case IOCTL_QMI_GET_SERVICE_FILE: | 1001 case IOCTL_QMI_GET_SERVICE_FILE: |
995 | 1002 |
996 DBG("Setting up QMI for service %lu\n", arg); | 1003 DBG("Setting up QMI for service %lu\n", arg); |
997 if (!(u8)arg) { | 1004 if (!(u8)arg) { |
998 DBG("Cannot use QMICTL from userspace\n"); | 1005 DBG("Cannot use QMICTL from userspace\n"); |
999 return -EINVAL; | 1006 return -EINVAL; |
1000 } | 1007 } |
1001 | 1008 |
1002 if (handle->cid != (u16)-1) { | 1009 if (handle->cid != (u16)-1) { |
1003 DBG("Close the current connection before opening a new o ne\n"); | 1010 DBG("Close the current connection before opening a new o ne\n"); |
1004 return -EBADR; | 1011 return -EBADR; |
1005 } | 1012 } |
1006 | 1013 |
1007 result = client_alloc(handle->dev, (u8)arg); | 1014 result = client_alloc(handle->dev, (u8)arg); |
1008 if (result < 0) | 1015 if (result < 0) |
1009 return result; | 1016 return result; |
1010 handle->cid = result; | 1017 handle->cid = result; |
1011 | 1018 |
1012 return 0; | 1019 return 0; |
1013 break; | 1020 break; |
1014 | 1021 |
1015 | |
1016 case IOCTL_QMI_GET_DEVICE_VIDPID: | 1022 case IOCTL_QMI_GET_DEVICE_VIDPID: |
1017 if (!arg) { | 1023 if (!arg) { |
1018 DBG("Bad VIDPID buffer\n"); | 1024 DBG("Bad VIDPID buffer\n"); |
1019 return -EINVAL; | 1025 return -EINVAL; |
1020 } | 1026 } |
1021 | 1027 |
1022 if (!handle->dev->usbnet) { | 1028 if (!handle->dev->usbnet) { |
1023 DBG("Bad usbnet\n"); | 1029 DBG("Bad usbnet\n"); |
1024 return -ENOMEM; | 1030 return -ENOMEM; |
1025 } | 1031 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1102 file->f_op = file->f_dentry->d_inode->i_fop; | 1108 file->f_op = file->f_dentry->d_inode->i_fop; |
1103 return -ENXIO; | 1109 return -ENXIO; |
1104 } | 1110 } |
1105 | 1111 |
1106 DBG("0x%04X\n", handle->cid); | 1112 DBG("0x%04X\n", handle->cid); |
1107 | 1113 |
1108 file->private_data = NULL; | 1114 file->private_data = NULL; |
1109 | 1115 |
1110 if (handle->cid != (u16)-1) | 1116 if (handle->cid != (u16)-1) |
1111 client_free(handle->dev, handle->cid); | 1117 client_free(handle->dev, handle->cid); |
1112 | 1118 » qcusbnet_put(handle->dev); |
1113 kfree(handle); | 1119 kfree(handle); |
1114 return 0; | 1120 return 0; |
1115 } | 1121 } |
1116 | 1122 |
1117 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, | 1123 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, |
1118 loff_t *pos) | 1124 loff_t *pos) |
1119 { | 1125 { |
1120 int result; | 1126 int result; |
1121 void *data = NULL; | 1127 void *data = NULL; |
1122 void *smalldata; | 1128 void *smalldata; |
1123 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1129 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
1124 | 1130 |
1125 if (!handle) { | 1131 if (!handle) { |
1126 DBG("Bad file data\n"); | 1132 DBG("Bad file data\n"); |
1127 return -EBADF; | 1133 return -EBADF; |
1128 } | 1134 } |
1129 | 1135 |
1136 if (handle->dev->dying) { | |
1137 DBG("Dying device"); | |
1138 return -ENXIO; | |
1139 } | |
1140 | |
1130 if (!device_valid(handle->dev)) { | 1141 if (!device_valid(handle->dev)) { |
1131 DBG("Invalid device! Updating f_ops\n"); | 1142 DBG("Invalid device! Updating f_ops\n"); |
1132 file->f_op = file->f_dentry->d_inode->i_fop; | 1143 file->f_op = file->f_dentry->d_inode->i_fop; |
1133 return -ENXIO; | 1144 return -ENXIO; |
1134 } | 1145 } |
1135 | 1146 |
1136 if (handle->cid == (u16)-1) { | 1147 if (handle->cid == (u16)-1) { |
1137 DBG("Client ID must be set before reading 0x%04X\n", | 1148 DBG("Client ID must be set before reading 0x%04X\n", |
1138 handle->cid); | 1149 handle->cid); |
1139 return -EBADR; | 1150 return -EBADR; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1205 } | 1216 } |
1206 | 1217 |
1207 int qc_register(struct qcusbnet *dev) | 1218 int qc_register(struct qcusbnet *dev) |
1208 { | 1219 { |
1209 int result; | 1220 int result; |
1210 int qmiidx = 0; | 1221 int qmiidx = 0; |
1211 dev_t devno; | 1222 dev_t devno; |
1212 char *name; | 1223 char *name; |
1213 | 1224 |
1214 dev->valid = true; | 1225 dev->valid = true; |
1226 dev->dying = false; | |
1215 result = client_alloc(dev, QMICTL); | 1227 result = client_alloc(dev, QMICTL); |
1216 if (result) { | 1228 if (result) { |
1217 dev->valid = false; | 1229 dev->valid = false; |
1218 return result; | 1230 return result; |
1219 } | 1231 } |
1220 atomic_set(&dev->qmi.qmitid, 1); | 1232 atomic_set(&dev->qmi.qmitid, 1); |
1221 | 1233 |
1222 result = qc_startread(dev); | 1234 result = qc_startread(dev); |
1223 if (result) { | 1235 if (result) { |
1224 dev->valid = false; | 1236 dev->valid = false; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1272 device_create(dev->qmi.devclass, NULL, devno, NULL, "qcqmi%d", qmiidx); | 1284 device_create(dev->qmi.devclass, NULL, devno, NULL, "qcqmi%d", qmiidx); |
1273 | 1285 |
1274 dev->qmi.devnum = devno; | 1286 dev->qmi.devnum = devno; |
1275 return 0; | 1287 return 0; |
1276 } | 1288 } |
1277 | 1289 |
1278 void qc_deregister(struct qcusbnet *dev) | 1290 void qc_deregister(struct qcusbnet *dev) |
1279 { | 1291 { |
1280 struct list_head *node, *tmp; | 1292 struct list_head *node, *tmp; |
1281 struct client *client; | 1293 struct client *client; |
1282 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 |