diff options
author | Johan Hovold <jhovold@gmail.com> | 2013-04-16 12:01:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-17 13:05:35 -0400 |
commit | feb0a36a523b9fd07275b12f76b344901f884253 (patch) | |
tree | 5c0f75fd2919887b2975a2dfc5190ab1e98c3619 | |
parent | 9c0343aa6cbbb62b8b829c87b15839f35bdebbf2 (diff) |
USB: kobil_sct: use port interrupt-out urb
Use the port interrupt-out urb rather than abusing the port write_urb
pointer and allocating a new urb at every open (but the first...).
Note that the write_urb abuse would have led to a double free should
there ever be interfaces with a bulk-out endpoint.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/serial/kobil_sct.c | 75 |
1 files changed, 8 insertions, 67 deletions
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 5bcfd57267f7..78b48c31abf5 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c | |||
@@ -65,7 +65,7 @@ static int kobil_tiocmget(struct tty_struct *tty); | |||
65 | static int kobil_tiocmset(struct tty_struct *tty, | 65 | static int kobil_tiocmset(struct tty_struct *tty, |
66 | unsigned int set, unsigned int clear); | 66 | unsigned int set, unsigned int clear); |
67 | static void kobil_read_int_callback(struct urb *urb); | 67 | static void kobil_read_int_callback(struct urb *urb); |
68 | static void kobil_write_callback(struct urb *purb); | 68 | static void kobil_write_int_callback(struct urb *urb); |
69 | static void kobil_set_termios(struct tty_struct *tty, | 69 | static void kobil_set_termios(struct tty_struct *tty, |
70 | struct usb_serial_port *port, struct ktermios *old); | 70 | struct usb_serial_port *port, struct ktermios *old); |
71 | static void kobil_init_termios(struct tty_struct *tty); | 71 | static void kobil_init_termios(struct tty_struct *tty); |
@@ -99,6 +99,7 @@ static struct usb_serial_driver kobil_device = { | |||
99 | .write = kobil_write, | 99 | .write = kobil_write, |
100 | .write_room = kobil_write_room, | 100 | .write_room = kobil_write_room, |
101 | .read_int_callback = kobil_read_int_callback, | 101 | .read_int_callback = kobil_read_int_callback, |
102 | .write_int_callback = kobil_write_int_callback, | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | static struct usb_serial_driver * const serial_drivers[] = { | 105 | static struct usb_serial_driver * const serial_drivers[] = { |
@@ -106,7 +107,6 @@ static struct usb_serial_driver * const serial_drivers[] = { | |||
106 | }; | 107 | }; |
107 | 108 | ||
108 | struct kobil_private { | 109 | struct kobil_private { |
109 | int write_int_endpoint_address; | ||
110 | unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */ | 110 | unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */ |
111 | int filled; /* index of the last char in buf */ | 111 | int filled; /* index of the last char in buf */ |
112 | int cur_pos; /* index of the next char to send in buf */ | 112 | int cur_pos; /* index of the next char to send in buf */ |
@@ -116,14 +116,8 @@ struct kobil_private { | |||
116 | 116 | ||
117 | static int kobil_port_probe(struct usb_serial_port *port) | 117 | static int kobil_port_probe(struct usb_serial_port *port) |
118 | { | 118 | { |
119 | int i; | ||
120 | struct usb_serial *serial = port->serial; | 119 | struct usb_serial *serial = port->serial; |
121 | struct kobil_private *priv; | 120 | struct kobil_private *priv; |
122 | struct usb_device *pdev; | ||
123 | struct usb_host_config *actconfig; | ||
124 | struct usb_interface *interface; | ||
125 | struct usb_host_interface *altsetting; | ||
126 | struct usb_host_endpoint *endpoint; | ||
127 | 121 | ||
128 | priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL); | 122 | priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL); |
129 | if (!priv) | 123 | if (!priv) |
@@ -149,23 +143,6 @@ static int kobil_port_probe(struct usb_serial_port *port) | |||
149 | } | 143 | } |
150 | usb_set_serial_port_data(port, priv); | 144 | usb_set_serial_port_data(port, priv); |
151 | 145 | ||
152 | /* search for the necessary endpoints */ | ||
153 | pdev = serial->dev; | ||
154 | actconfig = pdev->actconfig; | ||
155 | interface = actconfig->interface[0]; | ||
156 | altsetting = interface->cur_altsetting; | ||
157 | endpoint = altsetting->endpoint; | ||
158 | |||
159 | for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { | ||
160 | endpoint = &altsetting->endpoint[i]; | ||
161 | if (usb_endpoint_is_int_out(&endpoint->desc)) { | ||
162 | dev_dbg(&serial->dev->dev, | ||
163 | "%s Found interrupt out endpoint. Address: %d\n", | ||
164 | __func__, endpoint->desc.bEndpointAddress); | ||
165 | priv->write_int_endpoint_address = | ||
166 | endpoint->desc.bEndpointAddress; | ||
167 | } | ||
168 | } | ||
169 | return 0; | 146 | return 0; |
170 | } | 147 | } |
171 | 148 | ||
@@ -197,7 +174,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
197 | struct kobil_private *priv; | 174 | struct kobil_private *priv; |
198 | unsigned char *transfer_buffer; | 175 | unsigned char *transfer_buffer; |
199 | int transfer_buffer_length = 8; | 176 | int transfer_buffer_length = 8; |
200 | int write_urb_transfer_buffer_length = 8; | ||
201 | 177 | ||
202 | priv = usb_get_serial_port_data(port); | 178 | priv = usb_get_serial_port_data(port); |
203 | 179 | ||
@@ -206,27 +182,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
206 | if (!transfer_buffer) | 182 | if (!transfer_buffer) |
207 | return -ENOMEM; | 183 | return -ENOMEM; |
208 | 184 | ||
209 | /* allocate write_urb */ | ||
210 | if (!port->write_urb) { | ||
211 | dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__); | ||
212 | port->write_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
213 | if (!port->write_urb) { | ||
214 | dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__); | ||
215 | kfree(transfer_buffer); | ||
216 | return -ENOMEM; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /* allocate memory for write_urb transfer buffer */ | ||
221 | port->write_urb->transfer_buffer = | ||
222 | kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); | ||
223 | if (!port->write_urb->transfer_buffer) { | ||
224 | kfree(transfer_buffer); | ||
225 | usb_free_urb(port->write_urb); | ||
226 | port->write_urb = NULL; | ||
227 | return -ENOMEM; | ||
228 | } | ||
229 | |||
230 | /* get hardware version */ | 185 | /* get hardware version */ |
231 | result = usb_control_msg(port->serial->dev, | 186 | result = usb_control_msg(port->serial->dev, |
232 | usb_rcvctrlpipe(port->serial->dev, 0), | 187 | usb_rcvctrlpipe(port->serial->dev, 0), |
@@ -302,12 +257,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
302 | static void kobil_close(struct usb_serial_port *port) | 257 | static void kobil_close(struct usb_serial_port *port) |
303 | { | 258 | { |
304 | /* FIXME: Add rts/dtr methods */ | 259 | /* FIXME: Add rts/dtr methods */ |
305 | if (port->write_urb) { | 260 | usb_kill_urb(port->interrupt_out_urb); |
306 | usb_poison_urb(port->write_urb); | ||
307 | kfree(port->write_urb->transfer_buffer); | ||
308 | usb_free_urb(port->write_urb); | ||
309 | port->write_urb = NULL; | ||
310 | } | ||
311 | usb_kill_urb(port->interrupt_in_urb); | 261 | usb_kill_urb(port->interrupt_in_urb); |
312 | } | 262 | } |
313 | 263 | ||
@@ -336,7 +286,7 @@ static void kobil_read_int_callback(struct urb *urb) | |||
336 | } | 286 | } |
337 | 287 | ||
338 | 288 | ||
339 | static void kobil_write_callback(struct urb *purb) | 289 | static void kobil_write_int_callback(struct urb *urb) |
340 | { | 290 | { |
341 | } | 291 | } |
342 | 292 | ||
@@ -379,23 +329,14 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
379 | 329 | ||
380 | while (todo > 0) { | 330 | while (todo > 0) { |
381 | /* max 8 byte in one urb (endpoint size) */ | 331 | /* max 8 byte in one urb (endpoint size) */ |
382 | length = (todo < 8) ? todo : 8; | 332 | length = min(todo, port->interrupt_out_size); |
383 | /* copy data to transfer buffer */ | 333 | /* copy data to transfer buffer */ |
384 | memcpy(port->write_urb->transfer_buffer, | 334 | memcpy(port->interrupt_out_buffer, |
385 | priv->buf + priv->cur_pos, length); | 335 | priv->buf + priv->cur_pos, length); |
386 | usb_fill_int_urb(port->write_urb, | 336 | port->interrupt_out_urb->transfer_buffer_length = length; |
387 | port->serial->dev, | ||
388 | usb_sndintpipe(port->serial->dev, | ||
389 | priv->write_int_endpoint_address), | ||
390 | port->write_urb->transfer_buffer, | ||
391 | length, | ||
392 | kobil_write_callback, | ||
393 | port, | ||
394 | 8 | ||
395 | ); | ||
396 | 337 | ||
397 | priv->cur_pos = priv->cur_pos + length; | 338 | priv->cur_pos = priv->cur_pos + length; |
398 | result = usb_submit_urb(port->write_urb, GFP_NOIO); | 339 | result = usb_submit_urb(port->interrupt_out_urb, GFP_NOIO); |
399 | dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result); | 340 | dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result); |
400 | todo = priv->filled - priv->cur_pos; | 341 | todo = priv->filled - priv->cur_pos; |
401 | 342 | ||