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