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 |