Commit fbf947736968cbb0e55ec4b5d861d31a4a106c99
Committed by
Greg Kroah-Hartman
1 parent
a6c042f950
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
USB: omninet: switch to generic read implementation
Switch to the more efficient generic read implementation. Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 3 additions and 40 deletions Inline Diff
drivers/usb/serial/omninet.c
1 | /* | 1 | /* |
2 | * USB ZyXEL omni.net LCD PLUS driver | 2 | * USB ZyXEL omni.net LCD PLUS driver |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License version | 5 | * modify it under the terms of the GNU General Public License version |
6 | * 2 as published by the Free Software Foundation. | 6 | * 2 as published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * See Documentation/usb/usb-serial.txt for more information on using this | 8 | * See Documentation/usb/usb-serial.txt for more information on using this |
9 | * driver | 9 | * driver |
10 | * | 10 | * |
11 | * Please report both successes and troubles to the author at omninet@kroah.com | 11 | * Please report both successes and troubles to the author at omninet@kroah.com |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/tty.h> | 18 | #include <linux/tty.h> |
19 | #include <linux/tty_driver.h> | 19 | #include <linux/tty_driver.h> |
20 | #include <linux/tty_flip.h> | 20 | #include <linux/tty_flip.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
23 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
24 | #include <linux/usb/serial.h> | 24 | #include <linux/usb/serial.h> |
25 | 25 | ||
26 | #define DRIVER_AUTHOR "Alessandro Zummo" | 26 | #define DRIVER_AUTHOR "Alessandro Zummo" |
27 | #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" | 27 | #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" |
28 | 28 | ||
29 | #define ZYXEL_VENDOR_ID 0x0586 | 29 | #define ZYXEL_VENDOR_ID 0x0586 |
30 | #define ZYXEL_OMNINET_ID 0x1000 | 30 | #define ZYXEL_OMNINET_ID 0x1000 |
31 | /* This one seems to be a re-branded ZyXEL device */ | 31 | /* This one seems to be a re-branded ZyXEL device */ |
32 | #define BT_IGNITIONPRO_ID 0x2000 | 32 | #define BT_IGNITIONPRO_ID 0x2000 |
33 | 33 | ||
34 | /* function prototypes */ | 34 | /* function prototypes */ |
35 | static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); | 35 | static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); |
36 | static void omninet_close(struct usb_serial_port *port); | 36 | static void omninet_process_read_urb(struct urb *urb); |
37 | static void omninet_read_bulk_callback(struct urb *urb); | ||
38 | static void omninet_write_bulk_callback(struct urb *urb); | 37 | static void omninet_write_bulk_callback(struct urb *urb); |
39 | static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, | 38 | static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, |
40 | const unsigned char *buf, int count); | 39 | const unsigned char *buf, int count); |
41 | static int omninet_write_room(struct tty_struct *tty); | 40 | static int omninet_write_room(struct tty_struct *tty); |
42 | static void omninet_disconnect(struct usb_serial *serial); | 41 | static void omninet_disconnect(struct usb_serial *serial); |
43 | static int omninet_port_probe(struct usb_serial_port *port); | 42 | static int omninet_port_probe(struct usb_serial_port *port); |
44 | static int omninet_port_remove(struct usb_serial_port *port); | 43 | static int omninet_port_remove(struct usb_serial_port *port); |
45 | 44 | ||
46 | static const struct usb_device_id id_table[] = { | 45 | static const struct usb_device_id id_table[] = { |
47 | { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, | 46 | { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, |
48 | { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, | 47 | { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, |
49 | { } /* Terminating entry */ | 48 | { } /* Terminating entry */ |
50 | }; | 49 | }; |
51 | MODULE_DEVICE_TABLE(usb, id_table); | 50 | MODULE_DEVICE_TABLE(usb, id_table); |
52 | 51 | ||
53 | static struct usb_serial_driver zyxel_omninet_device = { | 52 | static struct usb_serial_driver zyxel_omninet_device = { |
54 | .driver = { | 53 | .driver = { |
55 | .owner = THIS_MODULE, | 54 | .owner = THIS_MODULE, |
56 | .name = "omninet", | 55 | .name = "omninet", |
57 | }, | 56 | }, |
58 | .description = "ZyXEL - omni.net lcd plus usb", | 57 | .description = "ZyXEL - omni.net lcd plus usb", |
59 | .id_table = id_table, | 58 | .id_table = id_table, |
60 | .num_ports = 1, | 59 | .num_ports = 1, |
61 | .port_probe = omninet_port_probe, | 60 | .port_probe = omninet_port_probe, |
62 | .port_remove = omninet_port_remove, | 61 | .port_remove = omninet_port_remove, |
63 | .open = omninet_open, | 62 | .open = omninet_open, |
64 | .close = omninet_close, | ||
65 | .write = omninet_write, | 63 | .write = omninet_write, |
66 | .write_room = omninet_write_room, | 64 | .write_room = omninet_write_room, |
67 | .read_bulk_callback = omninet_read_bulk_callback, | ||
68 | .write_bulk_callback = omninet_write_bulk_callback, | 65 | .write_bulk_callback = omninet_write_bulk_callback, |
66 | .process_read_urb = omninet_process_read_urb, | ||
69 | .disconnect = omninet_disconnect, | 67 | .disconnect = omninet_disconnect, |
70 | }; | 68 | }; |
71 | 69 | ||
72 | static struct usb_serial_driver * const serial_drivers[] = { | 70 | static struct usb_serial_driver * const serial_drivers[] = { |
73 | &zyxel_omninet_device, NULL | 71 | &zyxel_omninet_device, NULL |
74 | }; | 72 | }; |
75 | 73 | ||
76 | 74 | ||
77 | /* | 75 | /* |
78 | * The protocol. | 76 | * The protocol. |
79 | * | 77 | * |
80 | * The omni.net always exchange 64 bytes of data with the host. The first | 78 | * The omni.net always exchange 64 bytes of data with the host. The first |
81 | * four bytes are the control header. | 79 | * four bytes are the control header. |
82 | * | 80 | * |
83 | * oh_seq is a sequence number. Don't know if/how it's used. | 81 | * oh_seq is a sequence number. Don't know if/how it's used. |
84 | * oh_len is the length of the data bytes in the packet. | 82 | * oh_len is the length of the data bytes in the packet. |
85 | * oh_xxx Bit-mapped, related to handshaking and status info. | 83 | * oh_xxx Bit-mapped, related to handshaking and status info. |
86 | * I normally set it to 0x03 in transmitted frames. | 84 | * I normally set it to 0x03 in transmitted frames. |
87 | * 7: Active when the TA is in a CONNECTed state. | 85 | * 7: Active when the TA is in a CONNECTed state. |
88 | * 6: unknown | 86 | * 6: unknown |
89 | * 5: handshaking, unknown | 87 | * 5: handshaking, unknown |
90 | * 4: handshaking, unknown | 88 | * 4: handshaking, unknown |
91 | * 3: unknown, usually 0 | 89 | * 3: unknown, usually 0 |
92 | * 2: unknown, usually 0 | 90 | * 2: unknown, usually 0 |
93 | * 1: handshaking, unknown, usually set to 1 in transmitted frames | 91 | * 1: handshaking, unknown, usually set to 1 in transmitted frames |
94 | * 0: handshaking, unknown, usually set to 1 in transmitted frames | 92 | * 0: handshaking, unknown, usually set to 1 in transmitted frames |
95 | * oh_pad Probably a pad byte. | 93 | * oh_pad Probably a pad byte. |
96 | * | 94 | * |
97 | * After the header you will find data bytes if oh_len was greater than zero. | 95 | * After the header you will find data bytes if oh_len was greater than zero. |
98 | */ | 96 | */ |
99 | struct omninet_header { | 97 | struct omninet_header { |
100 | __u8 oh_seq; | 98 | __u8 oh_seq; |
101 | __u8 oh_len; | 99 | __u8 oh_len; |
102 | __u8 oh_xxx; | 100 | __u8 oh_xxx; |
103 | __u8 oh_pad; | 101 | __u8 oh_pad; |
104 | }; | 102 | }; |
105 | 103 | ||
106 | struct omninet_data { | 104 | struct omninet_data { |
107 | __u8 od_outseq; /* Sequence number for bulk_out URBs */ | 105 | __u8 od_outseq; /* Sequence number for bulk_out URBs */ |
108 | }; | 106 | }; |
109 | 107 | ||
110 | static int omninet_port_probe(struct usb_serial_port *port) | 108 | static int omninet_port_probe(struct usb_serial_port *port) |
111 | { | 109 | { |
112 | struct omninet_data *od; | 110 | struct omninet_data *od; |
113 | 111 | ||
114 | od = kzalloc(sizeof(*od), GFP_KERNEL); | 112 | od = kzalloc(sizeof(*od), GFP_KERNEL); |
115 | if (!od) | 113 | if (!od) |
116 | return -ENOMEM; | 114 | return -ENOMEM; |
117 | 115 | ||
118 | usb_set_serial_port_data(port, od); | 116 | usb_set_serial_port_data(port, od); |
119 | 117 | ||
120 | return 0; | 118 | return 0; |
121 | } | 119 | } |
122 | 120 | ||
123 | static int omninet_port_remove(struct usb_serial_port *port) | 121 | static int omninet_port_remove(struct usb_serial_port *port) |
124 | { | 122 | { |
125 | struct omninet_data *od; | 123 | struct omninet_data *od; |
126 | 124 | ||
127 | od = usb_get_serial_port_data(port); | 125 | od = usb_get_serial_port_data(port); |
128 | kfree(od); | 126 | kfree(od); |
129 | 127 | ||
130 | return 0; | 128 | return 0; |
131 | } | 129 | } |
132 | 130 | ||
133 | static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) | 131 | static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) |
134 | { | 132 | { |
135 | struct usb_serial *serial = port->serial; | 133 | struct usb_serial *serial = port->serial; |
136 | struct usb_serial_port *wport; | 134 | struct usb_serial_port *wport; |
137 | int result = 0; | ||
138 | 135 | ||
139 | wport = serial->port[1]; | 136 | wport = serial->port[1]; |
140 | tty_port_tty_set(&wport->port, tty); | 137 | tty_port_tty_set(&wport->port, tty); |
141 | 138 | ||
142 | /* Start reading from the device */ | 139 | return usb_serial_generic_open(tty, port); |
143 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
144 | if (result) | ||
145 | dev_err(&port->dev, | ||
146 | "%s - failed submitting read urb, error %d\n", | ||
147 | __func__, result); | ||
148 | return result; | ||
149 | } | 140 | } |
150 | 141 | ||
151 | static void omninet_close(struct usb_serial_port *port) | ||
152 | { | ||
153 | usb_kill_urb(port->read_urb); | ||
154 | } | ||
155 | |||
156 | |||
157 | #define OMNINET_HEADERLEN 4 | 142 | #define OMNINET_HEADERLEN 4 |
158 | #define OMNINET_BULKOUTSIZE 64 | 143 | #define OMNINET_BULKOUTSIZE 64 |
159 | #define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN) | 144 | #define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN) |
160 | 145 | ||
161 | static void omninet_process_read_urb(struct urb *urb) | 146 | static void omninet_process_read_urb(struct urb *urb) |
162 | { | 147 | { |
163 | struct usb_serial_port *port = urb->context; | 148 | struct usb_serial_port *port = urb->context; |
164 | const struct omninet_header *hdr = urb->transfer_buffer; | 149 | const struct omninet_header *hdr = urb->transfer_buffer; |
165 | const unsigned char *data; | 150 | const unsigned char *data; |
166 | size_t data_len; | 151 | size_t data_len; |
167 | 152 | ||
168 | if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len) | 153 | if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len) |
169 | return; | 154 | return; |
170 | 155 | ||
171 | data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN; | 156 | data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN; |
172 | data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN, | 157 | data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN, |
173 | hdr->oh_len); | 158 | hdr->oh_len); |
174 | tty_insert_flip_string(&port->port, data, data_len); | 159 | tty_insert_flip_string(&port->port, data, data_len); |
175 | tty_flip_buffer_push(&port->port); | 160 | tty_flip_buffer_push(&port->port); |
176 | } | ||
177 | |||
178 | static void omninet_read_bulk_callback(struct urb *urb) | ||
179 | { | ||
180 | struct usb_serial_port *port = urb->context; | ||
181 | int status = urb->status; | ||
182 | int result; | ||
183 | |||
184 | if (status) { | ||
185 | dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n", | ||
186 | __func__, status); | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | omninet_process_read_urb(urb); | ||
191 | |||
192 | /* Continue trying to always read */ | ||
193 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
194 | if (result) | ||
195 | dev_err(&port->dev, | ||
196 | "%s - failed resubmitting read urb, error %d\n", | ||
197 | __func__, result); | ||
198 | } | 161 | } |
199 | 162 | ||
200 | static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, | 163 | static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, |
201 | const unsigned char *buf, int count) | 164 | const unsigned char *buf, int count) |
202 | { | 165 | { |
203 | struct usb_serial *serial = port->serial; | 166 | struct usb_serial *serial = port->serial; |
204 | struct usb_serial_port *wport = serial->port[1]; | 167 | struct usb_serial_port *wport = serial->port[1]; |
205 | 168 | ||
206 | struct omninet_data *od = usb_get_serial_port_data(port); | 169 | struct omninet_data *od = usb_get_serial_port_data(port); |
207 | struct omninet_header *header = (struct omninet_header *) | 170 | struct omninet_header *header = (struct omninet_header *) |
208 | wport->write_urb->transfer_buffer; | 171 | wport->write_urb->transfer_buffer; |
209 | 172 | ||
210 | int result; | 173 | int result; |
211 | 174 | ||
212 | if (count == 0) { | 175 | if (count == 0) { |
213 | dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); | 176 | dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); |
214 | return 0; | 177 | return 0; |
215 | } | 178 | } |
216 | 179 | ||
217 | if (!test_and_clear_bit(0, &port->write_urbs_free)) { | 180 | if (!test_and_clear_bit(0, &port->write_urbs_free)) { |
218 | dev_dbg(&port->dev, "%s - already writing\n", __func__); | 181 | dev_dbg(&port->dev, "%s - already writing\n", __func__); |
219 | return 0; | 182 | return 0; |
220 | } | 183 | } |
221 | 184 | ||
222 | count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; | 185 | count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; |
223 | 186 | ||
224 | memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, | 187 | memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, |
225 | buf, count); | 188 | buf, count); |
226 | 189 | ||
227 | usb_serial_debug_data(&port->dev, __func__, count, | 190 | usb_serial_debug_data(&port->dev, __func__, count, |
228 | wport->write_urb->transfer_buffer); | 191 | wport->write_urb->transfer_buffer); |
229 | 192 | ||
230 | header->oh_seq = od->od_outseq++; | 193 | header->oh_seq = od->od_outseq++; |
231 | header->oh_len = count; | 194 | header->oh_len = count; |
232 | header->oh_xxx = 0x03; | 195 | header->oh_xxx = 0x03; |
233 | header->oh_pad = 0x00; | 196 | header->oh_pad = 0x00; |
234 | 197 | ||
235 | /* send the data out the bulk port, always 64 bytes */ | 198 | /* send the data out the bulk port, always 64 bytes */ |
236 | wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; | 199 | wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; |
237 | 200 | ||
238 | result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); | 201 | result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); |
239 | if (result) { | 202 | if (result) { |
240 | set_bit(0, &wport->write_urbs_free); | 203 | set_bit(0, &wport->write_urbs_free); |
241 | dev_err_console(port, | 204 | dev_err_console(port, |
242 | "%s - failed submitting write urb, error %d\n", | 205 | "%s - failed submitting write urb, error %d\n", |
243 | __func__, result); | 206 | __func__, result); |
244 | } else | 207 | } else |
245 | result = count; | 208 | result = count; |
246 | 209 | ||
247 | return result; | 210 | return result; |
248 | } | 211 | } |
249 | 212 | ||
250 | 213 | ||
251 | static int omninet_write_room(struct tty_struct *tty) | 214 | static int omninet_write_room(struct tty_struct *tty) |
252 | { | 215 | { |
253 | struct usb_serial_port *port = tty->driver_data; | 216 | struct usb_serial_port *port = tty->driver_data; |
254 | struct usb_serial *serial = port->serial; | 217 | struct usb_serial *serial = port->serial; |
255 | struct usb_serial_port *wport = serial->port[1]; | 218 | struct usb_serial_port *wport = serial->port[1]; |
256 | 219 | ||
257 | int room = 0; /* Default: no room */ | 220 | int room = 0; /* Default: no room */ |
258 | 221 | ||
259 | if (test_bit(0, &wport->write_urbs_free)) | 222 | if (test_bit(0, &wport->write_urbs_free)) |
260 | room = wport->bulk_out_size - OMNINET_HEADERLEN; | 223 | room = wport->bulk_out_size - OMNINET_HEADERLEN; |
261 | 224 | ||
262 | dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); | 225 | dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); |
263 | 226 | ||
264 | return room; | 227 | return room; |
265 | } | 228 | } |
266 | 229 | ||
267 | static void omninet_write_bulk_callback(struct urb *urb) | 230 | static void omninet_write_bulk_callback(struct urb *urb) |
268 | { | 231 | { |
269 | /* struct omninet_header *header = (struct omninet_header *) | 232 | /* struct omninet_header *header = (struct omninet_header *) |
270 | urb->transfer_buffer; */ | 233 | urb->transfer_buffer; */ |
271 | struct usb_serial_port *port = urb->context; | 234 | struct usb_serial_port *port = urb->context; |
272 | int status = urb->status; | 235 | int status = urb->status; |
273 | 236 | ||
274 | set_bit(0, &port->write_urbs_free); | 237 | set_bit(0, &port->write_urbs_free); |
275 | if (status) { | 238 | if (status) { |
276 | dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", | 239 | dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", |
277 | __func__, status); | 240 | __func__, status); |
278 | return; | 241 | return; |
279 | } | 242 | } |
280 | 243 | ||
281 | usb_serial_port_softint(port); | 244 | usb_serial_port_softint(port); |
282 | } | 245 | } |
283 | 246 | ||
284 | 247 | ||
285 | static void omninet_disconnect(struct usb_serial *serial) | 248 | static void omninet_disconnect(struct usb_serial *serial) |
286 | { | 249 | { |
287 | struct usb_serial_port *wport = serial->port[1]; | 250 | struct usb_serial_port *wport = serial->port[1]; |
288 | 251 | ||
289 | usb_kill_urb(wport->write_urb); | 252 | usb_kill_urb(wport->write_urb); |
290 | } | 253 | } |
291 | 254 | ||
292 | module_usb_serial_driver(serial_drivers, id_table); | 255 | module_usb_serial_driver(serial_drivers, id_table); |
293 | 256 | ||
294 | MODULE_AUTHOR(DRIVER_AUTHOR); | 257 | MODULE_AUTHOR(DRIVER_AUTHOR); |
295 | MODULE_DESCRIPTION(DRIVER_DESC); | 258 | MODULE_DESCRIPTION(DRIVER_DESC); |
296 | MODULE_LICENSE("GPL"); | 259 | MODULE_LICENSE("GPL"); |