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 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
725 urb = client_delurb(dev, cid); | 725 urb = client_delurb(dev, cid); |
726 } | 726 } |
727 | 727 |
728 while (client_delread(dev, cid, 0, &data, &size)) | 728 while (client_delread(dev, cid, 0, &data, &size)) |
729 kfree(data); | 729 kfree(data); |
730 | 730 |
731 list_del(&client->node); | 731 list_del(&client->node); |
732 kfree(client); | 732 kfree(client); |
733 } | 733 } |
734 } | 734 } |
735 | |
736 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); | 735 spin_unlock_irqrestore(&dev->qmi.clients_lock, flags); |
737 } | 736 } |
738 | 737 |
739 struct client *client_bycid(struct qcusbnet *dev, u16 cid) | 738 struct client *client_bycid(struct qcusbnet *dev, u16 cid) |
740 { | 739 { |
741 struct list_head *node; | 740 struct list_head *node; |
742 struct client *client; | 741 struct client *client; |
743 | 742 |
744 if (!device_valid(dev)) { | 743 if (!device_valid(dev)) { |
745 DBG("Invalid device\n"); | 744 DBG("Invalid device\n"); |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
939 kfree(req); | 938 kfree(req); |
940 return urb; | 939 return urb; |
941 } | 940 } |
942 | 941 |
943 static int devqmi_open(struct inode *inode, struct file *file) | 942 static int devqmi_open(struct inode *inode, struct file *file) |
944 { | 943 { |
945 struct qmihandle *handle; | 944 struct qmihandle *handle; |
946 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev) ; | 945 struct qmidev *qmidev = container_of(inode->i_cdev, struct qmidev, cdev) ; |
947 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi); | 946 struct qcusbnet *dev = container_of(qmidev, struct qcusbnet, qmi); |
948 | 947 |
949 » if (!device_valid(dev)) { | 948 » /* We need an extra ref on the device per fd, since we stash a ref |
950 » » DBG("Invalid device\n"); | 949 » * inside the handle. If qcusbnet_get() returns NULL, that means the |
950 » * device has been removed from the list - no new refs for us. */ | |
951 » struct qcusbnet *ref = qcusbnet_get(dev); | |
952 | |
953 » if (!ref) | |
951 return -ENXIO; | 954 return -ENXIO; |
952 } | |
953 | 955 |
954 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); | 956 file->private_data = kmalloc(sizeof(struct qmihandle), GFP_KERNEL); |
955 if (!file->private_data) { | 957 if (!file->private_data) { |
956 DBG("Mem error\n"); | 958 DBG("Mem error\n"); |
957 return -ENOMEM; | 959 return -ENOMEM; |
958 } | 960 } |
959 | 961 |
960 handle = (struct qmihandle *)file->private_data; | 962 handle = (struct qmihandle *)file->private_data; |
961 handle->cid = (u16)-1; | 963 handle->cid = (u16)-1; |
962 » handle->dev = dev; | 964 » handle->dev = ref; |
963 | 965 |
964 DBG("%p %04x", handle, handle->cid); | 966 DBG("%p %04x", handle, handle->cid); |
965 | 967 |
966 return 0; | 968 return 0; |
967 } | 969 } |
968 | 970 |
969 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg) | 971 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg) |
970 { | 972 { |
971 int result; | 973 int result; |
972 u32 vidpid; | 974 u32 vidpid; |
973 | 975 |
974 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 976 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
975 | 977 |
976 DBG("%p %04x %08x", handle, handle->cid, cmd); | 978 DBG("%p %04x %08x", handle, handle->cid, cmd); |
977 | 979 |
978 if (!handle) { | 980 if (!handle) { |
979 DBG("Bad file data\n"); | 981 DBG("Bad file data\n"); |
980 return -EBADF; | 982 return -EBADF; |
981 } | 983 } |
982 | 984 |
985 if (handle->dev->dying) { | |
Mandeep Singh Baines
2011/03/16 20:49:41
Why isn't device_valid sufficient?
Elly Fong-Jones
2011/03/16 21:23:09
To avoid racing against the loop in qc_deregister(
| |
986 DBG("Dying device"); | |
987 return -ENXIO; | |
988 } | |
989 | |
983 if (!device_valid(handle->dev)) { | 990 if (!device_valid(handle->dev)) { |
984 DBG("Invalid device!\n"); | 991 DBG("Invalid device!\n"); |
985 return -ENXIO; | 992 return -ENXIO; |
986 } | 993 } |
987 | 994 |
988 switch (cmd) { | 995 switch (cmd) { |
989 case IOCTL_QMI_GET_SERVICE_FILE: | 996 case IOCTL_QMI_GET_SERVICE_FILE: |
990 | 997 |
991 DBG("Setting up QMI for service %lu\n", arg); | 998 DBG("Setting up QMI for service %lu\n", arg); |
992 if (!(u8)arg) { | 999 if (!(u8)arg) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1077 } | 1084 } |
1078 | 1085 |
1079 static int devqmi_release(struct inode *inode, struct file *file) | 1086 static int devqmi_release(struct inode *inode, struct file *file) |
1080 { | 1087 { |
1081 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1088 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
1082 if (!handle) | 1089 if (!handle) |
1083 return 0; | 1090 return 0; |
1084 file->private_data = NULL; | 1091 file->private_data = NULL; |
1085 if (handle->cid != (u16)-1) | 1092 if (handle->cid != (u16)-1) |
1086 client_free(handle->dev, handle->cid); | 1093 client_free(handle->dev, handle->cid); |
1094 qcusbnet_put(handle->dev); | |
1087 kfree(handle); | 1095 kfree(handle); |
1088 return 0; | 1096 return 0; |
1089 } | 1097 } |
1090 | 1098 |
1091 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, | 1099 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, |
1092 loff_t *pos) | 1100 loff_t *pos) |
1093 { | 1101 { |
1094 int result; | 1102 int result; |
1095 void *data = NULL; | 1103 void *data = NULL; |
1096 void *smalldata; | 1104 void *smalldata; |
1097 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1105 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
1098 | 1106 |
1099 if (!handle) { | 1107 if (!handle) { |
1100 DBG("Bad file data\n"); | 1108 DBG("Bad file data\n"); |
1101 return -EBADF; | 1109 return -EBADF; |
1102 } | 1110 } |
1103 | 1111 |
1112 if (handle->dev->dying) { | |
1113 DBG("Dying device"); | |
1114 return -ENXIO; | |
1115 } | |
1116 | |
1104 if (!device_valid(handle->dev)) { | 1117 if (!device_valid(handle->dev)) { |
1105 DBG("Invalid device!\n"); | 1118 DBG("Invalid device!\n"); |
1106 return -ENXIO; | 1119 return -ENXIO; |
1107 } | 1120 } |
1108 | 1121 |
1109 if (handle->cid == (u16)-1) { | 1122 if (handle->cid == (u16)-1) { |
1110 DBG("Client ID must be set before reading 0x%04X\n", | 1123 DBG("Client ID must be set before reading 0x%04X\n", |
1111 handle->cid); | 1124 handle->cid); |
1112 return -EBADR; | 1125 return -EBADR; |
1113 } | 1126 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1178 } | 1191 } |
1179 | 1192 |
1180 int qc_register(struct qcusbnet *dev) | 1193 int qc_register(struct qcusbnet *dev) |
1181 { | 1194 { |
1182 int result; | 1195 int result; |
1183 int qmiidx = 0; | 1196 int qmiidx = 0; |
1184 dev_t devno; | 1197 dev_t devno; |
1185 char *name; | 1198 char *name; |
1186 | 1199 |
1187 dev->valid = true; | 1200 dev->valid = true; |
1201 dev->dying = false; | |
1188 result = client_alloc(dev, QMICTL); | 1202 result = client_alloc(dev, QMICTL); |
1189 if (result) { | 1203 if (result) { |
1190 dev->valid = false; | 1204 dev->valid = false; |
1191 return result; | 1205 return result; |
1192 } | 1206 } |
1193 atomic_set(&dev->qmi.qmitid, 1); | 1207 atomic_set(&dev->qmi.qmitid, 1); |
1194 | 1208 |
1195 result = qc_startread(dev); | 1209 result = qc_startread(dev); |
1196 if (result) { | 1210 if (result) { |
1197 dev->valid = false; | 1211 dev->valid = false; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1245 device_create(dev->qmi.devclass, &dev->iface->dev, devno, NULL, "qcqmi%d ", qmiidx); | 1259 device_create(dev->qmi.devclass, &dev->iface->dev, devno, NULL, "qcqmi%d ", qmiidx); |
1246 | 1260 |
1247 dev->qmi.devnum = devno; | 1261 dev->qmi.devnum = devno; |
1248 return 0; | 1262 return 0; |
1249 } | 1263 } |
1250 | 1264 |
1251 void qc_deregister(struct qcusbnet *dev) | 1265 void qc_deregister(struct qcusbnet *dev) |
1252 { | 1266 { |
1253 struct list_head *node, *tmp; | 1267 struct list_head *node, *tmp; |
1254 struct client *client; | 1268 struct client *client; |
1255 struct inode *inode; | |
1256 struct list_head *inodes; | |
1257 struct task_struct *task; | |
1258 struct fdtable *fdtable; | |
1259 struct file *file; | |
1260 unsigned long flags; | |
1261 int count = 0; | |
1262 | 1269 |
1270 dev->dying = true; | |
1263 list_for_each_safe(node, tmp, &dev->qmi.clients) { | 1271 list_for_each_safe(node, tmp, &dev->qmi.clients) { |
1264 client = list_entry(node, struct client, node); | 1272 client = list_entry(node, struct client, node); |
1265 DBG("release 0x%04X\n", client->cid); | 1273 DBG("release 0x%04X\n", client->cid); |
1266 client_free(dev, client->cid); | 1274 client_free(dev, client->cid); |
1267 } | 1275 } |
1268 | 1276 |
1269 qc_stopread(dev); | 1277 qc_stopread(dev); |
1270 dev->valid = false; | 1278 dev->valid = false; |
1271 list_for_each(inodes, &dev->qmi.cdev.list) { | |
1272 inode = container_of(inodes, struct inode, i_devices); | |
1273 if (inode != NULL && !IS_ERR(inode)) { | |
1274 rcu_read_lock(); | |
1275 for_each_process(task) { | |
1276 if (!task || !task->files) | |
1277 continue; | |
1278 spin_lock_irqsave(&task->files->file_lock, flags ); | |
1279 fdtable = files_fdtable(task->files); | |
1280 for (count = 0; count < fdtable->max_fds; count+ +) { | |
1281 file = fdtable->fd[count]; | |
1282 if (file != NULL && file->f_dentry != N ULL) { | |
1283 if (file->f_dentry->d_inode == i node) { | |
1284 rcu_assign_pointer(fdtab le->fd[count], NULL); | |
1285 spin_unlock_irqrestore(& task->files->file_lock, flags); | |
1286 DBG("forcing close of op en file handle\n"); | |
1287 filp_close(file, task->f iles); | |
1288 spin_lock_irqsave(&task- >files->file_lock, flags); | |
1289 } | |
1290 } | |
1291 } | |
1292 spin_unlock_irqrestore(&task->files->file_lock, flags); | |
1293 } | |
1294 rcu_read_unlock(); | |
1295 } | |
1296 } | |
1297 | |
1298 if (!IS_ERR(dev->qmi.devclass)) | 1279 if (!IS_ERR(dev->qmi.devclass)) |
1299 device_destroy(dev->qmi.devclass, dev->qmi.devnum); | 1280 device_destroy(dev->qmi.devclass, dev->qmi.devnum); |
1300 cdev_del(&dev->qmi.cdev); | 1281 cdev_del(&dev->qmi.cdev); |
1301 unregister_chrdev_region(dev->qmi.devnum, 1); | 1282 unregister_chrdev_region(dev->qmi.devnum, 1); |
1302 } | 1283 } |
1303 | 1284 |
1304 static bool qmi_ready(struct qcusbnet *dev, u16 timeout) | 1285 static bool qmi_ready(struct qcusbnet *dev, u16 timeout) |
1305 { | 1286 { |
1306 int result; | 1287 int result; |
1307 void *wbuf; | 1288 void *wbuf; |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1553 DBG("bad get MEID resp\n"); | 1534 DBG("bad get MEID resp\n"); |
1554 memset(&dev->meid[0], '0', 14); | 1535 memset(&dev->meid[0], '0', 14); |
1555 } | 1536 } |
1556 | 1537 |
1557 client_free(dev, cid); | 1538 client_free(dev, cid); |
1558 return 0; | 1539 return 0; |
1559 } | 1540 } |
1560 | 1541 |
1561 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); | 1542 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); |
1562 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); | 1543 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); |
OLD | NEW |