diff options
author | Richard Ash <richard@audacityteam.org> | 2009-07-29 12:12:18 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-15 15:01:35 -0400 |
commit | 72ba94ec61d1ceb9b80e317f72548b1e88e539f4 (patch) | |
tree | cef2dffd9d26b02f25160abf53602fbdd320ee72 /drivers/staging/quatech_usb2 | |
parent | c4f3020fc40b7977090dba42e1165db653408440 (diff) |
Staging: quatech_usb2: implement open functionality
Part two of the driver implementation has finally got done. It
implements the rest of open and the callback for reads from the box. I
seem to have finally found a structure that can be made to work, with a
single set of URBs for bulk read and write for the whole device, which
are used by all the ports. I've rationalised a few things, but there
will still be a lot of clean-up needed.
This one definitely can panic the kernel when a port is opened for
reading, but I'm off on holiday so I thought I'd post where I have got
to so far. I haven't tried to debug why it panics with a null pointer
dereference yet.
Signed-off-by: Richard Ash <richard@audacityteam.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/quatech_usb2')
-rw-r--r-- | drivers/staging/quatech_usb2/quatech_usb2.c | 584 |
1 files changed, 515 insertions, 69 deletions
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c index 3544e700540..0eaea2e7ce8 100644 --- a/drivers/staging/quatech_usb2/quatech_usb2.c +++ b/drivers/staging/quatech_usb2/quatech_usb2.c | |||
@@ -38,6 +38,7 @@ static int debug; | |||
38 | #define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */ | 38 | #define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */ |
39 | #define QU2BOX232 0x40 /* RS232 mode on MEI devices */ | 39 | #define QU2BOX232 0x40 /* RS232 mode on MEI devices */ |
40 | #define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */ | 40 | #define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */ |
41 | #define FIFO_DEPTH 1024 /* size of hardware fifos */ | ||
41 | /* directions for USB transfers */ | 42 | /* directions for USB transfers */ |
42 | #define USBD_TRANSFER_DIRECTION_IN 0xc0 | 43 | #define USBD_TRANSFER_DIRECTION_IN 0xc0 |
43 | #define USBD_TRANSFER_DIRECTION_OUT 0x40 | 44 | #define USBD_TRANSFER_DIRECTION_OUT 0x40 |
@@ -84,6 +85,12 @@ static int debug; | |||
84 | #define SERIAL_LSR_FE 0x08 | 85 | #define SERIAL_LSR_FE 0x08 |
85 | #define SERIAL_LSR_BI 0x10 | 86 | #define SERIAL_LSR_BI 0x10 |
86 | 87 | ||
88 | /* handy macros for doing escape sequence parsing on data reads */ | ||
89 | #define THISCHAR ((unsigned char *)(urb->transfer_buffer))[i] | ||
90 | #define NEXTCHAR ((unsigned char *)(urb->transfer_buffer))[i + 1] | ||
91 | #define THIRDCHAR ((unsigned char *)(urb->transfer_buffer))[i + 2] | ||
92 | #define FOURTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 3] | ||
93 | #define FIFTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 4] | ||
87 | 94 | ||
88 | static struct usb_device_id quausb2_id_table[] = { | 95 | static struct usb_device_id quausb2_id_table[] = { |
89 | {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, | 96 | {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, |
@@ -99,8 +106,6 @@ static struct usb_device_id quausb2_id_table[] = { | |||
99 | MODULE_DEVICE_TABLE(usb, quausb2_id_table); | 106 | MODULE_DEVICE_TABLE(usb, quausb2_id_table); |
100 | 107 | ||
101 | /* custom structures we need go here */ | 108 | /* custom structures we need go here */ |
102 | |||
103 | |||
104 | static struct usb_driver quausb2_usb_driver = { | 109 | static struct usb_driver quausb2_usb_driver = { |
105 | .name = "quatech-usb2-serial", | 110 | .name = "quatech-usb2-serial", |
106 | .probe = usb_serial_probe, | 111 | .probe = usb_serial_probe, |
@@ -109,10 +114,35 @@ static struct usb_driver quausb2_usb_driver = { | |||
109 | .no_dynamic_id = 1, | 114 | .no_dynamic_id = 1, |
110 | }; | 115 | }; |
111 | 116 | ||
112 | /* structure in which to keep all the messy stuff that this driver needs | 117 | /** structure in which to keep all the messy stuff that this driver needs |
113 | * alongside the usb_serial_port structure */ | 118 | * alongside the usb_serial_port structure |
119 | * @param read_urb_busy Flag indicating that port->read_urb is in use | ||
120 | * @param close_pending flag indicating that this port is in the process of | ||
121 | * being closed. | ||
122 | * @param shadowLSR Last received state of the line status register, holds the | ||
123 | * value of the line status flags from the port | ||
124 | * @param shadowMSR Last received state of the modem status register, holds | ||
125 | * the value of the modem status received from the port | ||
126 | * @param xmit_pending_bytes Number of bytes waiting to be sent out of | ||
127 | * the serial port | ||
128 | * @param xmit_fifo_room_bytes free space available in the transmit fifo | ||
129 | * for this port on the box | ||
130 | * @param rcv_flush Flag indicating that a receive flush has been requested by | ||
131 | * the hardware. | ||
132 | * @param xmit_flush Flag indicating that a transmit flush has been requested by | ||
133 | * the hardware. | ||
134 | */ | ||
114 | struct quatech2_port { | 135 | struct quatech2_port { |
115 | int magic; | 136 | int magic; |
137 | bool read_urb_busy; | ||
138 | bool close_pending; | ||
139 | __u8 shadowLSR; | ||
140 | __u8 shadowMSR; | ||
141 | int xmit_pending_bytes; | ||
142 | int xmit_fifo_room_bytes; | ||
143 | char rcv_flush; | ||
144 | char xmit_flush; | ||
145 | |||
116 | char active; /* someone has this device open */ | 146 | char active; /* someone has this device open */ |
117 | unsigned char *xfer_to_tty_buffer; | 147 | unsigned char *xfer_to_tty_buffer; |
118 | wait_queue_head_t wait; | 148 | wait_queue_head_t wait; |
@@ -120,20 +150,27 @@ struct quatech2_port { | |||
120 | struct semaphore sem; /* locks this structure */ | 150 | struct semaphore sem; /* locks this structure */ |
121 | __u8 shadowLCR; /* last LCR value received */ | 151 | __u8 shadowLCR; /* last LCR value received */ |
122 | __u8 shadowMCR; /* last MCR value received */ | 152 | __u8 shadowMCR; /* last MCR value received */ |
123 | __u8 shadowMSR; /* last MSR value received */ | ||
124 | __u8 shadowLSR; /* last LSR value received */ | ||
125 | char open_ports; /* ports open on whole device */ | ||
126 | char RxHolding; | 153 | char RxHolding; |
127 | char Rcv_Flush; | ||
128 | char Xmit_Flush; | ||
129 | char closePending; | ||
130 | char fifo_empty_flag; | 154 | char fifo_empty_flag; |
131 | int xmit_pending_bytes; | ||
132 | int xmit_fifo_room_bytes; | ||
133 | struct semaphore pend_xmit_sem; /* locks this structure */ | 155 | struct semaphore pend_xmit_sem; /* locks this structure */ |
134 | spinlock_t lock; | 156 | spinlock_t lock; |
135 | }; | 157 | }; |
136 | 158 | ||
159 | /** | ||
160 | * Structure to hold device-wide internal status information | ||
161 | * @param ReadBulkStopped The last bulk read attempt ended in tears | ||
162 | * @param open_ports The number of serial ports currently in use on the box | ||
163 | * @param current_port Pointer to the serial port structure of the port which | ||
164 | * the read stream is currently directed to. Escape sequences in the read | ||
165 | * stream will change this around as data arrives from different ports on the | ||
166 | * box | ||
167 | */ | ||
168 | struct quatech2_dev { | ||
169 | bool ReadBulkStopped; | ||
170 | char open_ports; | ||
171 | struct usb_serial_port *current_port; | ||
172 | }; | ||
173 | |||
137 | /* structure which holds line and modem status flags */ | 174 | /* structure which holds line and modem status flags */ |
138 | struct qt2_status_data { | 175 | struct qt2_status_data { |
139 | __u8 line_status; | 176 | __u8 line_status; |
@@ -152,12 +189,30 @@ static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port | |||
152 | *port); | 189 | *port); |
153 | static inline void qt2_set_port_private(struct usb_serial_port *port, | 190 | static inline void qt2_set_port_private(struct usb_serial_port *port, |
154 | struct quatech2_port *data); | 191 | struct quatech2_port *data); |
192 | static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial | ||
193 | *serial); | ||
194 | static inline void qt2_set_dev_private(struct usb_serial *serial, | ||
195 | struct quatech2_dev *data); | ||
155 | static int qt2_openboxchannel(struct usb_serial *serial, __u16 | 196 | static int qt2_openboxchannel(struct usb_serial *serial, __u16 |
156 | Uart_Number, struct qt2_status_data *pDeviceData); | 197 | Uart_Number, struct qt2_status_data *pDeviceData); |
157 | static int qt2_closeboxchannel(struct usb_serial *serial, __u16 | 198 | static int qt2_closeboxchannel(struct usb_serial *serial, __u16 |
158 | Uart_Number); | 199 | Uart_Number); |
159 | static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number, | 200 | static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number, |
160 | unsigned short divisor, unsigned char LCR); | 201 | unsigned short divisor, unsigned char LCR); |
202 | static void qt2_read_bulk_callback(struct urb *urb); | ||
203 | static void qt2_process_line_status(struct usb_serial_port *port, | ||
204 | unsigned char LineStatus); | ||
205 | static void qt2_process_modem_status(struct usb_serial_port *port, | ||
206 | unsigned char ModemStatus); | ||
207 | static void qt2_process_xmit_empty(struct usb_serial_port *port, | ||
208 | unsigned char fourth_char, unsigned char fifth_char); | ||
209 | static void qt2_process_port_change(struct usb_serial_port *port, | ||
210 | unsigned char New_Current_Port); | ||
211 | static void qt2_process_rcv_flush(struct usb_serial_port *port); | ||
212 | static void qt2_process_xmit_flush(struct usb_serial_port *port); | ||
213 | static void qt2_process_rx_char(struct usb_serial_port *port, | ||
214 | unsigned char data); | ||
215 | |||
161 | /* implementation functions, roughly in order of use, are here */ | 216 | /* implementation functions, roughly in order of use, are here */ |
162 | static int qt2_calc_num_ports(struct usb_serial *serial) | 217 | static int qt2_calc_num_ports(struct usb_serial *serial) |
163 | { | 218 | { |
@@ -195,12 +250,13 @@ static int qt2_calc_num_ports(struct usb_serial *serial) | |||
195 | static int qt2_attach(struct usb_serial *serial) | 250 | static int qt2_attach(struct usb_serial *serial) |
196 | { | 251 | { |
197 | struct usb_serial_port *port; | 252 | struct usb_serial_port *port; |
198 | struct quatech2_port *qt2_port; | 253 | struct quatech2_port *qt2_port; /* port-specific private data pointer */ |
254 | struct quatech2_dev *qt2_dev; /* dev-specific private data pointer */ | ||
199 | int i; | 255 | int i; |
200 | /* stuff for printing endpoint addresses, not needed for | 256 | /* stuff for storing endpoint addresses now */ |
201 | * production */ | ||
202 | struct usb_endpoint_descriptor *endpoint; | 257 | struct usb_endpoint_descriptor *endpoint; |
203 | struct usb_host_interface *iface_desc; | 258 | struct usb_host_interface *iface_desc; |
259 | struct usb_serial_port *port0; /* first port structure on device */ | ||
204 | 260 | ||
205 | /* check how many endpoints there are on the device, for | 261 | /* check how many endpoints there are on the device, for |
206 | * sanity's sake */ | 262 | * sanity's sake */ |
@@ -212,12 +268,42 @@ static int qt2_attach(struct usb_serial *serial) | |||
212 | return -ENODEV; | 268 | return -ENODEV; |
213 | } | 269 | } |
214 | iface_desc = serial->interface->cur_altsetting; | 270 | iface_desc = serial->interface->cur_altsetting; |
271 | |||
272 | /* Set up per-device private data, storing extra data alongside | ||
273 | * struct usb_serial */ | ||
274 | qt2_dev = kzalloc(sizeof(*qt2_dev), GFP_KERNEL); | ||
275 | if (!qt2_dev) { | ||
276 | dbg("%s: kmalloc for quatech2_dev failed!", | ||
277 | __func__); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | qt2_dev->open_ports = 0; /* no ports open */ | ||
281 | qt2_set_dev_private(serial, qt2_dev); /* store private data */ | ||
282 | |||
283 | /* Now setup per port private data, which replaces all the things | ||
284 | * that quatech added to standard kernel structures in their driver */ | ||
285 | for (i = 0; i < serial->num_ports; i++) { | ||
286 | port = serial->port[i]; | ||
287 | qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL); | ||
288 | if (!qt2_port) { | ||
289 | dbg("%s: kmalloc for quatech2_port (%d) failed!.", | ||
290 | __func__, i); | ||
291 | return -ENOMEM; | ||
292 | } | ||
293 | spin_lock_init(&qt2_port->lock); | ||
294 | usb_set_serial_port_data(port, qt2_port); | ||
295 | } | ||
296 | |||
297 | /* gain access to port[0]'s structure because we want to store | ||
298 | * device-level stuff in it */ | ||
299 | if (serial_paranoia_check(serial, __func__)) | ||
300 | return -ENODEV; | ||
301 | port0 = serial->port[0]; /* get the first port's device structure */ | ||
302 | |||
215 | /* print endpoint addresses so we can check them later | 303 | /* print endpoint addresses so we can check them later |
216 | * by hand */ | 304 | * by hand */ |
217 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | 305 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
218 | { | ||
219 | endpoint = &iface_desc->endpoint[i].desc; | 306 | endpoint = &iface_desc->endpoint[i].desc; |
220 | |||
221 | if ((endpoint->bEndpointAddress & 0x80) && | 307 | if ((endpoint->bEndpointAddress & 0x80) && |
222 | ((endpoint->bmAttributes & 3) == 0x02)) { | 308 | ((endpoint->bmAttributes & 3) == 0x02)) { |
223 | /* we found a bulk in endpoint */ | 309 | /* we found a bulk in endpoint */ |
@@ -226,33 +312,13 @@ static int qt2_attach(struct usb_serial *serial) | |||
226 | } | 312 | } |
227 | 313 | ||
228 | if (((endpoint->bEndpointAddress & 0x80) == 0x00) && | 314 | if (((endpoint->bEndpointAddress & 0x80) == 0x00) && |
229 | ((endpoint->bmAttributes & 3) == 0x02)) | 315 | ((endpoint->bmAttributes & 3) == 0x02)) { |
230 | { | ||
231 | /* we found a bulk out endpoint */ | 316 | /* we found a bulk out endpoint */ |
232 | dbg("found bulk out at 0x%x", | 317 | dbg("found bulk out at 0x%x", |
233 | endpoint->bEndpointAddress); | 318 | endpoint->bEndpointAddress); |
234 | } | 319 | } |
235 | } /* end printing endpoint addresses */ | 320 | } /* end printing endpoint addresses */ |
236 | 321 | ||
237 | /* Now setup per port private data, which replaces all the things | ||
238 | * that quatech added to standard kernel structures in their driver */ | ||
239 | for (i = 0; i < serial->num_ports; i++) { | ||
240 | port = serial->port[i]; | ||
241 | qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL); | ||
242 | if (!qt2_port) { | ||
243 | dbg("%s: kmalloc for quatech2_port (%d) failed!.", | ||
244 | __func__, i); | ||
245 | return -ENOMEM; | ||
246 | } | ||
247 | spin_lock_init(&qt2_port->lock); | ||
248 | if (i == 0) | ||
249 | qt2_port->open_ports = 0; /* no ports */ | ||
250 | else | ||
251 | qt2_port->open_ports = -1; /* unused */ | ||
252 | |||
253 | usb_set_serial_port_data(port, qt2_port); | ||
254 | |||
255 | } | ||
256 | /* switch on power to the hardware */ | 322 | /* switch on power to the hardware */ |
257 | if (qt2_boxpoweron(serial) < 0) { | 323 | if (qt2_boxpoweron(serial) < 0) { |
258 | dbg("qt2_boxpoweron() failed"); | 324 | dbg("qt2_boxpoweron() failed"); |
@@ -274,8 +340,11 @@ startup_error: | |||
274 | port = serial->port[i]; | 340 | port = serial->port[i]; |
275 | qt2_port = qt2_get_port_private(port); | 341 | qt2_port = qt2_get_port_private(port); |
276 | kfree(qt2_port); | 342 | kfree(qt2_port); |
277 | usb_set_serial_port_data(port, NULL); | 343 | qt2_set_port_private(port, NULL); |
278 | } | 344 | } |
345 | qt2_dev = qt2_get_dev_private(serial); | ||
346 | kfree(qt2_dev); | ||
347 | qt2_set_dev_private(serial, NULL); | ||
279 | 348 | ||
280 | dbg("Exit fail %s\n", __func__); | 349 | dbg("Exit fail %s\n", __func__); |
281 | return -EIO; | 350 | return -EIO; |
@@ -317,30 +386,40 @@ int qt2_open(struct tty_struct *tty, | |||
317 | struct usb_serial_port *port0; /* first port structure on device */ | 386 | struct usb_serial_port *port0; /* first port structure on device */ |
318 | struct quatech2_port *port_extra; /* extra data for this port */ | 387 | struct quatech2_port *port_extra; /* extra data for this port */ |
319 | struct quatech2_port *port0_extra; /* extra data for first port */ | 388 | struct quatech2_port *port0_extra; /* extra data for first port */ |
389 | struct quatech2_dev *dev_extra; /* extra data for the device */ | ||
320 | struct qt2_status_data ChannelData; | 390 | struct qt2_status_data ChannelData; |
321 | unsigned short default_divisor = QU2BOXSPD9600; | 391 | unsigned short default_divisor = QU2BOXSPD9600; |
322 | unsigned char default_LCR = SERIAL_8_DATA; | 392 | unsigned char default_LCR = SERIAL_8_DATA; |
323 | int status; | 393 | int status; |
394 | int result; | ||
324 | 395 | ||
325 | if (port_paranoia_check(port, __func__)) | 396 | if (port_paranoia_check(port, __func__)) |
326 | return -ENODEV; | 397 | return -ENODEV; |
327 | 398 | ||
328 | dbg("%s - port %d\n", __func__, port->number); | 399 | dbg("%s(): port %d", __func__, port->number); |
329 | 400 | ||
330 | serial = port->serial; /* get the parent device structure */ | 401 | serial = port->serial; /* get the parent device structure */ |
331 | if (serial_paranoia_check(serial, __func__)) | 402 | if (serial_paranoia_check(serial, __func__)) { |
403 | dbg("usb_serial struct failed sanity check"); | ||
332 | return -ENODEV; | 404 | return -ENODEV; |
405 | } | ||
406 | dev_extra = qt2_get_dev_private(serial); | ||
407 | /* get the device private data */ | ||
333 | port0 = serial->port[0]; /* get the first port's device structure */ | 408 | port0 = serial->port[0]; /* get the first port's device structure */ |
334 | 409 | if (port_paranoia_check(port, __func__)) { | |
410 | dbg("port0 usb_serial_port struct failed sanity check"); | ||
411 | return -ENODEV; | ||
412 | } | ||
335 | port_extra = qt2_get_port_private(port); | 413 | port_extra = qt2_get_port_private(port); |
336 | port0_extra = qt2_get_port_private(port0); | 414 | port0_extra = qt2_get_port_private(port0); |
337 | 415 | ||
338 | if (port_extra == NULL || port0_extra == NULL) | 416 | if (port_extra == NULL || port0_extra == NULL) { |
417 | dbg("failed to get private data for port and port0"); | ||
339 | return -ENODEV; | 418 | return -ENODEV; |
419 | } | ||
340 | 420 | ||
341 | usb_clear_halt(serial->dev, port->write_urb->pipe); | 421 | usb_clear_halt(serial->dev, port->write_urb->pipe); |
342 | usb_clear_halt(serial->dev, port->read_urb->pipe); | 422 | usb_clear_halt(serial->dev, port->read_urb->pipe); |
343 | port0_extra->open_ports++; | ||
344 | 423 | ||
345 | /* FIXME: are these needed? Does it even do anything useful? */ | 424 | /* FIXME: are these needed? Does it even do anything useful? */ |
346 | /* get the modem and line status values from the UART */ | 425 | /* get the modem and line status values from the UART */ |
@@ -374,39 +453,58 @@ int qt2_open(struct tty_struct *tty, | |||
374 | dbg("qt2_conf_uart() completed on channel %d", | 453 | dbg("qt2_conf_uart() completed on channel %d", |
375 | port->number); | 454 | port->number); |
376 | 455 | ||
377 | dbg("port number is %d", port->number); | 456 | /* |
378 | dbg("serial number is %d", port->serial->minor); | 457 | * At this point we will need some end points to make further progress. |
379 | 458 | * Handlily, the correct endpoint addresses have been filled out into | |
380 | /* We need to set up endpoints here. We only | 459 | * the usb_serial_port structure for us by the driver core, so we |
381 | * have one pair of endpoints per device, so in fact | 460 | * already have access to them. |
382 | * we only need to set up endpoints on the first time | 461 | * As there is only one bulk in and one bulk out end-point, these are in |
383 | * round, not subsequent ones. | 462 | * port[0]'s structure, and the rest are uninitialised. Handily, |
384 | * When we do a write to a port, we will use the same endpoint | 463 | * when we do a write to a port, we will use the same endpoint |
385 | * regardless of the port, with a 5-byte header added on to | 464 | * regardless of the port, with a 5-byte header added on to |
386 | * tell the box which port it should eventually come out of, | 465 | * tell the box which port it should eventually come out of, so we only |
387 | * so the same endpoint information needs to be visible to | 466 | * need the one set of endpoints. |
388 | * write calls regardless of which port is being written. | 467 | * Finally we need a bulk in URB to use for background reads from the |
389 | * To this end we actually keep the relevant endpoints | 468 | * device, which will deal with uplink data from the box to host. |
390 | * in port 0's structure, because that's always there | ||
391 | * and avoids providing our own duplicate members in some | ||
392 | * user data structure for the same purpose. | ||
393 | * URBs will be allocated and freed dynamically as the are | ||
394 | * used, so are not touched here. | ||
395 | */ | 469 | */ |
396 | if (port0_extra->open_ports == 1) { | 470 | dbg("port number is %d", port->number); |
397 | /* this is first port to be opened */ | 471 | dbg("serial number is %d", port->serial->minor); |
472 | dbg("port0 bulk in endpoint is %#.2x", port0->bulk_in_endpointAddress); | ||
473 | dbg("port0 bulk out endpoint is %#.2x", | ||
474 | port0->bulk_out_endpointAddress); | ||
475 | |||
476 | if (dev_extra->open_ports == 0) { | ||
477 | /* this is first port to be opened, so need some URBs */ | ||
478 | /* initialise read_urb for bulk in transfers */ | ||
479 | usb_fill_bulk_urb(port0->read_urb, serial->dev, | ||
480 | usb_rcvbulkpipe(serial->dev, | ||
481 | port0->bulk_in_endpointAddress), | ||
482 | port0->bulk_in_buffer, | ||
483 | port0->bulk_in_size, | ||
484 | qt2_read_bulk_callback, serial); | ||
485 | dbg("port0 bulk in URB intialised"); | ||
486 | |||
487 | /* submit URB, i.e. start reading from device (async) */ | ||
488 | dev_extra->ReadBulkStopped = false; | ||
489 | port_extra->read_urb_busy = true; | ||
490 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
491 | if (result) { | ||
492 | dev_err(&port->dev, | ||
493 | "%s - Error %d submitting bulk in urb\n", | ||
494 | __func__, result); | ||
495 | port_extra->read_urb_busy = false; | ||
496 | } | ||
398 | } | 497 | } |
399 | 498 | ||
400 | dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress); | ||
401 | dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress); | ||
402 | dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress); | ||
403 | |||
404 | /* initialize our wait queues */ | 499 | /* initialize our wait queues */ |
405 | init_waitqueue_head(&port_extra->wait); | 500 | init_waitqueue_head(&port_extra->wait); |
406 | 501 | ||
407 | /* remember to store port_extra and port0 back again at end !*/ | 502 | /* remember to store port_extra and port0 back again at end !*/ |
408 | qt2_set_port_private(port, port_extra); | 503 | qt2_set_port_private(port, port_extra); |
409 | qt2_set_port_private(serial->port[0], port0_extra); | 504 | qt2_set_port_private(serial->port[0], port0_extra); |
505 | qt2_set_dev_private(serial, dev_extra); | ||
506 | |||
507 | dev_extra->open_ports++; /* one more port opened */ | ||
410 | 508 | ||
411 | return 0; | 509 | return 0; |
412 | } | 510 | } |
@@ -486,11 +584,22 @@ static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port | |||
486 | } | 584 | } |
487 | 585 | ||
488 | static inline void qt2_set_port_private(struct usb_serial_port *port, | 586 | static inline void qt2_set_port_private(struct usb_serial_port *port, |
489 | struct quatech2_port *data) | 587 | struct quatech2_port *data) |
490 | { | 588 | { |
491 | usb_set_serial_port_data(port, (void *)data); | 589 | usb_set_serial_port_data(port, (void *)data); |
492 | } | 590 | } |
493 | 591 | ||
592 | static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial | ||
593 | *serial) | ||
594 | { | ||
595 | return (struct quatech2_dev *)usb_get_serial_data(serial); | ||
596 | } | ||
597 | static inline void qt2_set_dev_private(struct usb_serial *serial, | ||
598 | struct quatech2_dev *data) | ||
599 | { | ||
600 | usb_set_serial_data(serial, (void *)data); | ||
601 | } | ||
602 | |||
494 | static int qt2_openboxchannel(struct usb_serial *serial, __u16 | 603 | static int qt2_openboxchannel(struct usb_serial *serial, __u16 |
495 | Uart_Number, struct qt2_status_data *status) | 604 | Uart_Number, struct qt2_status_data *status) |
496 | { | 605 | { |
@@ -534,6 +643,343 @@ static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number, | |||
534 | return result; | 643 | return result; |
535 | } | 644 | } |
536 | 645 | ||
646 | /** @brief Callback for asynchronous submission of URBs on bulk in | ||
647 | * endpoints | ||
648 | * | ||
649 | * Registered in qt2_open_port(), used to deal with incomming data | ||
650 | * from the box. | ||
651 | */ | ||
652 | static void qt2_read_bulk_callback(struct urb *urb) | ||
653 | { | ||
654 | /* Get the device pointer (struct usb_serial) back out of the URB */ | ||
655 | struct usb_serial *serial = urb->context; | ||
656 | /* get the extra struct for the device */ | ||
657 | struct quatech2_dev *dev_extra = qt2_get_dev_private(serial); | ||
658 | /* Get first port structure from the device */ | ||
659 | struct usb_serial_port *port0 = serial->port[0]; | ||
660 | /* Get the currently active port structure from serial struct */ | ||
661 | struct usb_serial_port *active = dev_extra->current_port; | ||
662 | /* get the extra struct for port 0 */ | ||
663 | struct quatech2_port *port0_extra = qt2_get_port_private(port0); | ||
664 | /* and for the currently active port */ | ||
665 | struct quatech2_port *active_extra = qt2_get_port_private(active); | ||
666 | /* When we finally get to doing some tty stuff, we will need this */ | ||
667 | struct tty_struct *tty_st; | ||
668 | unsigned int RxCount; /* the length of the data to process */ | ||
669 | unsigned int i; /* loop counter over the data to process */ | ||
670 | int result; /* return value cache variable */ | ||
671 | bool escapeflag; /* flag set to true if this loop iteration is | ||
672 | * parsing an escape sequence, rather than | ||
673 | * ordinary data */ | ||
674 | |||
675 | |||
676 | dbg("%s(): callback running", __func__); | ||
677 | |||
678 | if (urb->status) { | ||
679 | /* read didn't go well */ | ||
680 | dev_extra->ReadBulkStopped = true; | ||
681 | dbg("%s(): nonzero write bulk status received: %d", | ||
682 | __func__, urb->status); | ||
683 | return; | ||
684 | } | ||
685 | |||
686 | /* inline port_sofrint() here */ | ||
687 | if (port_paranoia_check(port0, __func__) != 0) { | ||
688 | dbg("%s - port_paranoia_check on port0 failed, exiting\n", | ||
689 | __func__); | ||
690 | return; | ||
691 | } | ||
692 | if (port_paranoia_check(active, __func__) != 0) { | ||
693 | dbg("%s - port_paranoia_check on current_port " | ||
694 | "failed, exiting", __func__); | ||
695 | return; | ||
696 | } | ||
697 | |||
698 | /* This single callback function has to do for all the ports on | ||
699 | * the device. Data being read up the USB can contain certain | ||
700 | * escape sequences which are used to communicate out-of-band | ||
701 | * information from the serial port in-band over the USB. | ||
702 | * These escapes include sending modem and flow control line | ||
703 | * status, and switching the port. The concept of a "Current Port" | ||
704 | * is used, which is where data is going until a port change | ||
705 | * escape seqence is received. This Current Port is kept between | ||
706 | * callbacks so that when this function enters we know which the | ||
707 | * currently active port is and can get to work right away without | ||
708 | * the box having to send repeat escape sequences (anyway, how | ||
709 | * would it know to do so?). | ||
710 | */ | ||
711 | |||
712 | if (active_extra->close_pending == true) { | ||
713 | /* We are closing , stop reading */ | ||
714 | dbg("%s - (active->close_pending == true", __func__); | ||
715 | if (dev_extra->open_ports <= 0) { | ||
716 | /* If this is the only port left open - stop the | ||
717 | * bulk read */ | ||
718 | dev_extra->ReadBulkStopped = true; | ||
719 | dbg("%s - (ReadBulkStopped == true;", __func__); | ||
720 | return; | ||
721 | } | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * RxHolding is asserted by throttle, if we assert it, we're not | ||
726 | * receiving any more characters and let the box handle the flow | ||
727 | * control | ||
728 | */ | ||
729 | if ((port0_extra->RxHolding == true) && | ||
730 | (serial->dev->descriptor.idProduct == QUATECH_SSU2_100)) { | ||
731 | /* single port device, input is already stopped, so we don't | ||
732 | * need any more input data */ | ||
733 | dev_extra->ReadBulkStopped = true; | ||
734 | return; | ||
735 | } | ||
736 | /* finally, we are in a situation where we might consider the data | ||
737 | * that is contained within the URB, and what to do about it. | ||
738 | * This is likely to involved communicating up to the TTY layer, so | ||
739 | * we will need to get hold of the tty for the port we are currently | ||
740 | * dealing with */ | ||
741 | |||
742 | /* active is a usb_serial_port. It has a member port which is a | ||
743 | * tty_port. From this we get a tty_struct pointer which is what we | ||
744 | * actually wanted, and keep it on tty_st */ | ||
745 | tty_st = tty_port_tty_get(&active->port); | ||
746 | if (!tty_st) { | ||
747 | dbg("%s - bad tty pointer - exiting", __func__); | ||
748 | return; | ||
749 | } | ||
750 | dbg("%s(): active port %d, tty_st =0x%p\n", __func__, active->number, | ||
751 | tty_st); | ||
752 | RxCount = urb->actual_length; /* grab length of data handy */ | ||
753 | |||
754 | if (RxCount) { | ||
755 | /* skip all this if no data to process */ | ||
756 | for (i = 0; i < RxCount ; ++i) { | ||
757 | /* Look ahead code here -works on several bytes at onc*/ | ||
758 | if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b) | ||
759 | && (NEXTCHAR == 0x1b)) { | ||
760 | /* we are in an escape sequence, type | ||
761 | * determined by the 3rd char */ | ||
762 | escapeflag = false; | ||
763 | switch (THIRDCHAR) { | ||
764 | case 0x00: | ||
765 | /* Line status change 4th byte must | ||
766 | * follow */ | ||
767 | if (i > (RxCount - 4)) { | ||
768 | dbg("Illegal escape sequences " | ||
769 | "in received data"); | ||
770 | break; | ||
771 | } | ||
772 | qt2_process_line_status(active, | ||
773 | FOURTHCHAR); | ||
774 | i += 3; | ||
775 | escapeflag = true; | ||
776 | break; | ||
777 | case 0x01: | ||
778 | /* Modem status status change 4th byte | ||
779 | * must follow */ | ||
780 | if (i > (RxCount - 4)) { | ||
781 | dbg("Illegal escape sequences " | ||
782 | "in received data"); | ||
783 | break; | ||
784 | } | ||
785 | qt2_process_modem_status(active, | ||
786 | FOURTHCHAR); | ||
787 | i += 3; | ||
788 | escapeflag = true; | ||
789 | break; | ||
790 | case 0x02: | ||
791 | /* xmit hold empty 4th byte | ||
792 | * must follow */ | ||
793 | if (i > (RxCount - 4)) { | ||
794 | dbg("Illegal escape sequences " | ||
795 | "in received data"); | ||
796 | break; | ||
797 | } | ||
798 | qt2_process_xmit_empty(active, | ||
799 | FOURTHCHAR, | ||
800 | FIFTHCHAR); | ||
801 | i += 4; | ||
802 | escapeflag = true; | ||
803 | break; | ||
804 | case 0x03: | ||
805 | /* Port number change 4th byte | ||
806 | * must follow */ | ||
807 | if (i > (RxCount - 4)) { | ||
808 | dbg("Illegal escape sequences " | ||
809 | "in received data"); | ||
810 | break; | ||
811 | } | ||
812 | /* Port change. If port open push | ||
813 | * current data up to tty layer */ | ||
814 | if (dev_extra->open_ports > 0) | ||
815 | tty_flip_buffer_push(tty_st); | ||
816 | |||
817 | dbg("Port Change: new port = %d", | ||
818 | FOURTHCHAR); | ||
819 | qt2_process_port_change(active, | ||
820 | FOURTHCHAR); | ||
821 | i += 3; | ||
822 | escapeflag = true; | ||
823 | /* having changed port, the pointers for | ||
824 | * the currently active port are all out | ||
825 | * of date and need updating */ | ||
826 | active = dev_extra->current_port; | ||
827 | active_extra = | ||
828 | qt2_get_port_private(active); | ||
829 | tty_st = tty_port_tty_get( | ||
830 | &active->port); | ||
831 | break; | ||
832 | case 0x04: | ||
833 | /* Recv flush 3rd byte must | ||
834 | * follow */ | ||
835 | if (i > (RxCount - 3)) { | ||
836 | dbg("Illegal escape sequences " | ||
837 | "in received data"); | ||
838 | break; | ||
839 | } | ||
840 | qt2_process_rcv_flush(active); | ||
841 | i += 2; | ||
842 | escapeflag = true; | ||
843 | break; | ||
844 | case 0x05: | ||
845 | /* xmit flush 3rd byte must follow */ | ||
846 | if (i > (RxCount - 3)) { | ||
847 | dbg("Illegal escape sequences " | ||
848 | "in received data"); | ||
849 | break; | ||
850 | } | ||
851 | qt2_process_xmit_flush(active); | ||
852 | i += 2; | ||
853 | escapeflag = true; | ||
854 | break; | ||
855 | case 0xff: | ||
856 | dbg("No status sequence"); | ||
857 | qt2_process_rx_char(active, THISCHAR); | ||
858 | qt2_process_rx_char(active, NEXTCHAR); | ||
859 | i += 2; | ||
860 | break; | ||
861 | default: | ||
862 | qt2_process_rx_char(active, THISCHAR); | ||
863 | i += 1; | ||
864 | break; | ||
865 | } /*end switch*/ | ||
866 | if (escapeflag == true) | ||
867 | continue; | ||
868 | /* if we did an escape char, we don't need | ||
869 | * to mess around pushing data through the | ||
870 | * tty layer, and can go round again */ | ||
871 | } /*endif*/ | ||
872 | if (tty_st && urb->actual_length) { | ||
873 | tty_buffer_request_room(tty_st, 1); | ||
874 | tty_insert_flip_string(tty_st, | ||
875 | &((unsigned char *)(urb->transfer_buffer) | ||
876 | )[i], | ||
877 | 1); | ||
878 | } | ||
879 | } /*endfor*/ | ||
880 | tty_flip_buffer_push(tty_st); | ||
881 | } /*endif*/ | ||
882 | |||
883 | /* at this point we have complete dealing with the data for this | ||
884 | * callback. All we have to do now is to start the async read process | ||
885 | * back off again. */ | ||
886 | |||
887 | usb_fill_bulk_urb(port0->read_urb, serial->dev, | ||
888 | usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress), | ||
889 | port0->bulk_in_buffer, port0->bulk_in_size, | ||
890 | qt2_read_bulk_callback, serial); | ||
891 | result = usb_submit_urb(port0->read_urb, GFP_ATOMIC); | ||
892 | if (result) { | ||
893 | dbg("%s(): failed resubmitting read urb, error %d", | ||
894 | __func__, result); | ||
895 | } else { | ||
896 | if (tty_st && RxCount) { | ||
897 | /* if some inbound data was processed, then | ||
898 | * we need to push that through the tty layer | ||
899 | */ | ||
900 | tty_flip_buffer_push(tty_st); | ||
901 | tty_schedule_flip(tty_st); | ||
902 | } | ||
903 | } | ||
904 | |||
905 | /* cribbed from serqt_usb2 driver, but not sure which work needs | ||
906 | * scheduling - port0 or currently active port? */ | ||
907 | /* schedule_work(&port->work); */ | ||
908 | |||
909 | return; | ||
910 | } | ||
911 | static void qt2_process_line_status(struct usb_serial_port *port, | ||
912 | unsigned char LineStatus) | ||
913 | { | ||
914 | /* obtain the private structure for the port */ | ||
915 | struct quatech2_port *port_extra = qt2_get_port_private(port); | ||
916 | port_extra->shadowLSR = LineStatus & (SERIAL_LSR_OE | SERIAL_LSR_PE | | ||
917 | SERIAL_LSR_FE | SERIAL_LSR_BI); | ||
918 | } | ||
919 | static void qt2_process_modem_status(struct usb_serial_port *port, | ||
920 | unsigned char ModemStatus) | ||
921 | { | ||
922 | /* obtain the private structure for the port */ | ||
923 | struct quatech2_port *port_extra = qt2_get_port_private(port); | ||
924 | port_extra->shadowMSR = ModemStatus; | ||
925 | /* ?? */ | ||
926 | wake_up_interruptible(&port_extra->wait); | ||
927 | } | ||
928 | |||
929 | static void qt2_process_xmit_empty(struct usb_serial_port *port, | ||
930 | unsigned char fourth_char, unsigned char fifth_char) | ||
931 | { | ||
932 | int byte_count; | ||
933 | /* obtain the private structure for the port */ | ||
934 | struct quatech2_port *port_extra = qt2_get_port_private(port); | ||
935 | |||
936 | byte_count = (int)(fifth_char * 16); | ||
937 | byte_count += (int)fourth_char; | ||
938 | port_extra->xmit_pending_bytes -= (int)byte_count; | ||
939 | port_extra->xmit_fifo_room_bytes = FIFO_DEPTH; | ||
940 | } | ||
941 | |||
942 | static void qt2_process_port_change(struct usb_serial_port *port, | ||
943 | unsigned char New_Current_Port) | ||
944 | { | ||
945 | /* obtain the parent usb serial device structure */ | ||
946 | struct usb_serial *serial = port->serial; | ||
947 | /* obtain the private structure for the device */ | ||
948 | struct quatech2_dev *dev_extra = qt2_get_dev_private(serial); | ||
949 | dev_extra->current_port = serial->port[New_Current_Port]; | ||
950 | /* what should I do with this? commented out in upstream | ||
951 | * driver */ | ||
952 | /*schedule_work(&port->work);*/ | ||
953 | } | ||
954 | |||
955 | static void qt2_process_rcv_flush(struct usb_serial_port *port) | ||
956 | { | ||
957 | /* obtain the private structure for the port */ | ||
958 | struct quatech2_port *port_extra = qt2_get_port_private(port); | ||
959 | port_extra->rcv_flush = true; | ||
960 | } | ||
961 | static void qt2_process_xmit_flush(struct usb_serial_port *port) | ||
962 | { | ||
963 | /* obtain the private structure for the port */ | ||
964 | struct quatech2_port *port_extra = qt2_get_port_private(port); | ||
965 | port_extra->xmit_flush = true; | ||
966 | } | ||
967 | |||
968 | static void qt2_process_rx_char(struct usb_serial_port *port, | ||
969 | unsigned char data) | ||
970 | { | ||
971 | /* get the tty_struct for this port */ | ||
972 | struct tty_struct *tty = tty_port_tty_get(&(port->port)); | ||
973 | /* get the URB with the data in to push */ | ||
974 | struct urb *urb = port->serial->port[0]->read_urb; | ||
975 | |||
976 | if (tty && urb->actual_length) { | ||
977 | tty_buffer_request_room(tty, 1); | ||
978 | tty_insert_flip_string(tty, &data, 1); | ||
979 | /* should this be commented out here? */ | ||
980 | /*tty_flip_buffer_push(tty);*/ | ||
981 | } | ||
982 | } | ||
537 | /* | 983 | /* |
538 | * last things in file: stuff to register this driver into the generic | 984 | * last things in file: stuff to register this driver into the generic |
539 | * USB serial framework. | 985 | * USB serial framework. |