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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 static bool client_delread(struct qcusbnet *dev, u16 cid, u16 tid, void **data, u16 *size); | 63 static bool client_delread(struct qcusbnet *dev, u16 cid, u16 tid, void **data, u16 *size); |
64 static bool client_addnotify(struct qcusbnet *dev, u16 cid, u16 tid, | 64 static bool client_addnotify(struct qcusbnet *dev, u16 cid, u16 tid, |
65 void (*hook)(struct qcusbnet *, u16 cid, void *), | 65 void (*hook)(struct qcusbnet *, u16 cid, void *), |
66 void *data); | 66 void *data); |
67 static bool client_notify(struct qcusbnet *dev, u16 cid, u16 tid); | 67 static bool client_notify(struct qcusbnet *dev, u16 cid, u16 tid); |
68 static bool client_addurb(struct qcusbnet *dev, u16 cid, struct urb *urb); | 68 static bool client_addurb(struct qcusbnet *dev, u16 cid, struct urb *urb); |
69 static struct urb *client_delurb(struct qcusbnet *dev, u16 cid); | 69 static struct urb *client_delurb(struct qcusbnet *dev, u16 cid); |
70 | 70 |
71 static int devqmi_open(struct inode *inode, struct file *file); | 71 static int devqmi_open(struct inode *inode, struct file *file); |
72 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg); | 72 static int devqmi_ioctl(struct inode *inode, struct file *file, unsigned int cmd , unsigned long arg); |
73 static int devqmi_close(struct file *file, fl_owner_t ftable); | 73 static int devqmi_release(struct inode *inode, struct file *file); |
74 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, | 74 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, |
75 loff_t *pos); | 75 loff_t *pos); |
76 static ssize_t devqmi_write(struct file *file, const char __user *buf, | 76 static ssize_t devqmi_write(struct file *file, const char __user *buf, |
77 size_t size, loff_t *pos); | 77 size_t size, loff_t *pos); |
78 | 78 |
79 static bool qmi_ready(struct qcusbnet *dev, u16 timeout); | 79 static bool qmi_ready(struct qcusbnet *dev, u16 timeout); |
80 static void wds_callback(struct qcusbnet *dev, u16 cid, void *data); | 80 static void wds_callback(struct qcusbnet *dev, u16 cid, void *data); |
81 static int setup_wds_callback(struct qcusbnet *dev); | 81 static int setup_wds_callback(struct qcusbnet *dev); |
82 static int qmidms_getmeid(struct qcusbnet *dev); | 82 static int qmidms_getmeid(struct qcusbnet *dev); |
83 | 83 |
84 #define IOCTL_QMI_GET_SERVICE_FILE» (0x8BE0 + 1) | 84 #define IOCTL_QMI_GET_SERVICE_FILE (0x8BE0 + 1) |
85 #define IOCTL_QMI_GET_DEVICE_VIDPID» (0x8BE0 + 2) | 85 #define IOCTL_QMI_GET_DEVICE_VIDPID (0x8BE0 + 2) |
86 #define IOCTL_QMI_GET_DEVICE_MEID» (0x8BE0 + 3) | 86 #define IOCTL_QMI_GET_DEVICE_MEID (0x8BE0 + 3) |
87 #define IOCTL_QMI_CLOSE (0x8BE0 + 4) | |
87 #define CDC_GET_ENCAPSULATED_RESPONSE 0x01A1ll | 88 #define CDC_GET_ENCAPSULATED_RESPONSE 0x01A1ll |
88 #define CDC_CONNECTION_SPEED_CHANGE 0x08000000002AA1ll | 89 #define CDC_CONNECTION_SPEED_CHANGE 0x08000000002AA1ll |
89 | 90 |
90 static const struct file_operations devqmi_fops = { | 91 static const struct file_operations devqmi_fops = { |
91 » .owner = THIS_MODULE, | 92 » .owner = THIS_MODULE, |
92 » .read = devqmi_read, | 93 » .read = devqmi_read, |
93 » .write = devqmi_write, | 94 » .write = devqmi_write, |
94 » .ioctl = devqmi_ioctl, | 95 » .ioctl = devqmi_ioctl, |
95 » .open = devqmi_open, | 96 » .open = devqmi_open, |
96 » .flush = devqmi_close, | 97 » .release = devqmi_release, |
97 }; | 98 }; |
98 | 99 |
99 #ifdef CONFIG_SMP | 100 #ifdef CONFIG_SMP |
100 static inline void assert_locked(struct qcusbnet *dev) | 101 static inline void assert_locked(struct qcusbnet *dev) |
101 { | 102 { |
102 BUG_ON(!spin_is_locked(&dev->qmi.clients_lock)); | 103 BUG_ON(!spin_is_locked(&dev->qmi.clients_lock)); |
103 } | 104 } |
104 #else | 105 #else |
105 static inline void assert_locked(struct qcusbnet *dev) | 106 static inline void assert_locked(struct qcusbnet *dev) |
106 { | 107 { |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
672 struct urb *urb; | 673 struct urb *urb; |
673 void *data; | 674 void *data; |
674 u16 size; | 675 u16 size; |
675 void *wbuf; | 676 void *wbuf; |
676 size_t wbufsize; | 677 size_t wbufsize; |
677 void *rbuf; | 678 void *rbuf; |
678 u16 rbufsize; | 679 u16 rbufsize; |
679 unsigned long flags; | 680 unsigned long flags; |
680 u8 tid; | 681 u8 tid; |
681 | 682 |
682 if (!device_valid(dev)) { | |
683 DBG("invalid device\n"); | |
684 return; | |
685 } | |
686 | |
687 DBG("releasing 0x%04X\n", cid); | 683 DBG("releasing 0x%04X\n", cid); |
688 | 684 |
689 if (cid != QMICTL) { | 685 if (cid != QMICTL) { |
690 tid = atomic_add_return(1, &dev->qmi.qmitid); | 686 tid = atomic_add_return(1, &dev->qmi.qmitid); |
691 if (!tid) | 687 if (!tid) |
692 tid = atomic_add_return(1, &dev->qmi.qmitid); | 688 tid = atomic_add_return(1, &dev->qmi.qmitid); |
693 wbuf = qmictl_new_releasecid(tid, cid, &wbufsize); | 689 wbuf = qmictl_new_releasecid(tid, cid, &wbufsize); |
694 if (!wbuf) { | 690 if (!wbuf) { |
695 DBG("memory error\n"); | 691 DBG("memory error\n"); |
696 } else { | 692 } else { |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
978 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 974 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
979 | 975 |
980 DBG("%p %04x %08x", handle, handle->cid, cmd); | 976 DBG("%p %04x %08x", handle, handle->cid, cmd); |
981 | 977 |
982 if (!handle) { | 978 if (!handle) { |
983 DBG("Bad file data\n"); | 979 DBG("Bad file data\n"); |
984 return -EBADF; | 980 return -EBADF; |
985 } | 981 } |
986 | 982 |
987 if (!device_valid(handle->dev)) { | 983 if (!device_valid(handle->dev)) { |
988 » » DBG("Invalid device! Updating f_ops\n"); | 984 » » DBG("Invalid device!\n"); |
989 » » file->f_op = file->f_dentry->d_inode->i_fop; | |
990 return -ENXIO; | 985 return -ENXIO; |
991 } | 986 } |
992 | 987 |
993 switch (cmd) { | 988 switch (cmd) { |
994 case IOCTL_QMI_GET_SERVICE_FILE: | 989 case IOCTL_QMI_GET_SERVICE_FILE: |
995 | 990 |
996 DBG("Setting up QMI for service %lu\n", arg); | 991 DBG("Setting up QMI for service %lu\n", arg); |
997 if (!(u8)arg) { | 992 if (!(u8)arg) { |
998 DBG("Cannot use QMICTL from userspace\n"); | 993 DBG("Cannot use QMICTL from userspace\n"); |
999 return -EINVAL; | 994 return -EINVAL; |
1000 } | 995 } |
1001 | 996 |
1002 if (handle->cid != (u16)-1) { | 997 if (handle->cid != (u16)-1) { |
1003 DBG("Close the current connection before opening a new o ne\n"); | 998 DBG("Close the current connection before opening a new o ne\n"); |
1004 return -EBADR; | 999 return -EBADR; |
1005 } | 1000 } |
1006 | 1001 |
1007 result = client_alloc(handle->dev, (u8)arg); | 1002 result = client_alloc(handle->dev, (u8)arg); |
1008 if (result < 0) | 1003 if (result < 0) |
1009 return result; | 1004 return result; |
1010 handle->cid = result; | 1005 handle->cid = result; |
1011 | 1006 |
1012 return 0; | 1007 return 0; |
1013 break; | 1008 break; |
1014 | 1009 |
1010 /* Okay, all aboard the nasty hack express. If we don't have this | |
1011 * ioctl() (and we just rely on userspace to close() the file | |
1012 * descriptors), if userspace has any refs left to this fd (like, say, a | |
1013 * pending read()), then the read might hang around forever. Userspace | |
1014 * needs a way to cause us to kick people off those waitqueues before | |
1015 * closing the fd for good. | |
1016 * | |
1017 * If this driver used workqueues, the correct approach here would | |
1018 * instead be to make the file descriptor select()able, and then just | |
1019 * use select() instead of aio in userspace (thus allowing us to get | |
1020 * away with one thread total and avoiding the recounting mess | |
1021 * altogether). | |
1022 */ | |
Mandeep Singh Baines
2011/03/15 20:56:31
I've read the comment but I'm still not getting th
| |
1023 case IOCTL_QMI_CLOSE: | |
1024 DBG("Tearing down QMI for service %lu", arg); | |
1025 if (handle->cid == (u16)-1) { | |
1026 DBG("no qmi cid"); | |
1027 return -EBADR; | |
1028 } | |
1029 | |
1030 file->private_data = NULL; | |
1031 client_free(handle->dev, handle->cid); | |
1032 kfree(handle); | |
1033 return 0; | |
1034 break; | |
1015 | 1035 |
1016 case IOCTL_QMI_GET_DEVICE_VIDPID: | 1036 case IOCTL_QMI_GET_DEVICE_VIDPID: |
1017 if (!arg) { | 1037 if (!arg) { |
1018 DBG("Bad VIDPID buffer\n"); | 1038 DBG("Bad VIDPID buffer\n"); |
1019 return -EINVAL; | 1039 return -EINVAL; |
1020 } | 1040 } |
1021 | 1041 |
1022 if (!handle->dev->usbnet) { | 1042 if (!handle->dev->usbnet) { |
1023 DBG("Bad usbnet\n"); | 1043 DBG("Bad usbnet\n"); |
1024 return -ENOMEM; | 1044 return -ENOMEM; |
(...skipping 24 matching lines...) Expand all Loading... | |
1049 if (result) | 1069 if (result) |
1050 DBG("copy to userspace failure\n"); | 1070 DBG("copy to userspace failure\n"); |
1051 | 1071 |
1052 return result; | 1072 return result; |
1053 break; | 1073 break; |
1054 default: | 1074 default: |
1055 return -EBADRQC; | 1075 return -EBADRQC; |
1056 } | 1076 } |
1057 } | 1077 } |
1058 | 1078 |
1059 static int devqmi_close(struct file *file, fl_owner_t ftable) | 1079 static int devqmi_release(struct inode *inode, struct file *file) |
1060 { | 1080 { |
1061 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1081 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
1062 » struct task_struct *task; | 1082 » if (!handle) |
1063 » struct fdtable *fdtable; | 1083 » » return 0; |
1064 » int count = 0; | |
1065 » int used = 0; | |
1066 » unsigned long flags; | |
1067 | |
1068 » if (!handle) { | |
1069 » » DBG("bad file data\n"); | |
1070 » » return -EBADF; | |
1071 » } | |
1072 | |
1073 » if (file_count(file) != 1) { | |
1074 » » rcu_read_lock(); | |
1075 » » for_each_process(task) { | |
1076 » » » if (!task || !task->files) | |
1077 » » » » continue; | |
1078 » » » spin_lock_irqsave(&task->files->file_lock, flags); | |
1079 » » » fdtable = files_fdtable(task->files); | |
1080 » » » for (count = 0; count < fdtable->max_fds; count++) { | |
1081 » » » » /* Before this function was called, this file wa s removed | |
1082 » » » » * from our task's file table so if we find it i n a file | |
1083 » » » » * table then it is being used by another task | |
1084 » » » » */ | |
1085 » » » » if (fdtable->fd[count] == file) { | |
1086 » » » » » used++; | |
1087 » » » » » break; | |
1088 » » » » } | |
1089 » » » } | |
1090 » » » spin_unlock_irqrestore(&task->files->file_lock, flags); | |
1091 » » } | |
1092 » » rcu_read_unlock(); | |
1093 | |
1094 » » if (used > 0) { | |
1095 » » » DBG("not closing, as this FD is open by %d other process \n", used); | |
1096 » » » return 0; | |
1097 » » } | |
1098 » } | |
1099 | |
1100 » if (!device_valid(handle->dev)) { | |
1101 » » DBG("Invalid device! Updating f_ops\n"); | |
1102 » » file->f_op = file->f_dentry->d_inode->i_fop; | |
1103 » » return -ENXIO; | |
1104 » } | |
1105 | |
1106 » DBG("0x%04X\n", handle->cid); | |
1107 | |
1108 file->private_data = NULL; | 1084 file->private_data = NULL; |
1109 | |
1110 if (handle->cid != (u16)-1) | 1085 if (handle->cid != (u16)-1) |
1111 client_free(handle->dev, handle->cid); | 1086 client_free(handle->dev, handle->cid); |
1112 | |
1113 kfree(handle); | 1087 kfree(handle); |
1114 return 0; | 1088 return 0; |
1115 } | 1089 } |
1116 | 1090 |
1117 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, | 1091 static ssize_t devqmi_read(struct file *file, char __user *buf, size_t size, |
1118 loff_t *pos) | 1092 loff_t *pos) |
1119 { | 1093 { |
1120 int result; | 1094 int result; |
1121 void *data = NULL; | 1095 void *data = NULL; |
1122 void *smalldata; | 1096 void *smalldata; |
1123 struct qmihandle *handle = (struct qmihandle *)file->private_data; | 1097 struct qmihandle *handle = (struct qmihandle *)file->private_data; |
1124 | 1098 |
1125 if (!handle) { | 1099 if (!handle) { |
1126 DBG("Bad file data\n"); | 1100 DBG("Bad file data\n"); |
1127 return -EBADF; | 1101 return -EBADF; |
1128 } | 1102 } |
1129 | 1103 |
1130 if (!device_valid(handle->dev)) { | 1104 if (!device_valid(handle->dev)) { |
1131 » » DBG("Invalid device! Updating f_ops\n"); | 1105 » » DBG("Invalid device!\n"); |
1132 » » file->f_op = file->f_dentry->d_inode->i_fop; | |
1133 return -ENXIO; | 1106 return -ENXIO; |
1134 } | 1107 } |
1135 | 1108 |
1136 if (handle->cid == (u16)-1) { | 1109 if (handle->cid == (u16)-1) { |
1137 DBG("Client ID must be set before reading 0x%04X\n", | 1110 DBG("Client ID must be set before reading 0x%04X\n", |
1138 handle->cid); | 1111 handle->cid); |
1139 return -EBADR; | 1112 return -EBADR; |
1140 } | 1113 } |
1141 | 1114 |
1142 result = read_sync(handle->dev, &data, handle->cid, 0); | 1115 result = read_sync(handle->dev, &data, handle->cid, 0); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1280 struct list_head *node, *tmp; | 1253 struct list_head *node, *tmp; |
1281 struct client *client; | 1254 struct client *client; |
1282 struct inode *inode; | 1255 struct inode *inode; |
1283 struct list_head *inodes; | 1256 struct list_head *inodes; |
1284 struct task_struct *task; | 1257 struct task_struct *task; |
1285 struct fdtable *fdtable; | 1258 struct fdtable *fdtable; |
1286 struct file *file; | 1259 struct file *file; |
1287 unsigned long flags; | 1260 unsigned long flags; |
1288 int count = 0; | 1261 int count = 0; |
1289 | 1262 |
1290 if (!device_valid(dev)) { | |
1291 DBG("wrong device\n"); | |
1292 return; | |
1293 } | |
1294 | |
1295 list_for_each_safe(node, tmp, &dev->qmi.clients) { | 1263 list_for_each_safe(node, tmp, &dev->qmi.clients) { |
1296 client = list_entry(node, struct client, node); | 1264 client = list_entry(node, struct client, node); |
1297 DBG("release 0x%04X\n", client->cid); | 1265 DBG("release 0x%04X\n", client->cid); |
1298 client_free(dev, client->cid); | 1266 client_free(dev, client->cid); |
1299 } | 1267 } |
1300 | 1268 |
1301 qc_stopread(dev); | 1269 qc_stopread(dev); |
1302 dev->valid = false; | 1270 dev->valid = false; |
1303 list_for_each(inodes, &dev->qmi.cdev.list) { | 1271 list_for_each(inodes, &dev->qmi.cdev.list) { |
1304 inode = container_of(inodes, struct inode, i_devices); | 1272 inode = container_of(inodes, struct inode, i_devices); |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1583 DBG("bad get MEID resp\n"); | 1551 DBG("bad get MEID resp\n"); |
1584 memset(&dev->meid[0], '0', 14); | 1552 memset(&dev->meid[0], '0', 14); |
1585 } | 1553 } |
1586 | 1554 |
1587 client_free(dev, cid); | 1555 client_free(dev, cid); |
1588 return 0; | 1556 return 0; |
1589 } | 1557 } |
1590 | 1558 |
1591 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); | 1559 module_param(qcusbnet2k_fwdelay, int, S_IRUGO | S_IWUSR); |
1592 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); | 1560 MODULE_PARM_DESC(qcusbnet2k_fwdelay, "Delay for old firmware"); |
OLD | NEW |