aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2013-04-16 12:01:26 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-17 13:05:35 -0400
commitfeb0a36a523b9fd07275b12f76b344901f884253 (patch)
tree5c0f75fd2919887b2975a2dfc5190ab1e98c3619
parent9c0343aa6cbbb62b8b829c87b15839f35bdebbf2 (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.c75
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);
65static int kobil_tiocmset(struct tty_struct *tty, 65static int kobil_tiocmset(struct tty_struct *tty,
66 unsigned int set, unsigned int clear); 66 unsigned int set, unsigned int clear);
67static void kobil_read_int_callback(struct urb *urb); 67static void kobil_read_int_callback(struct urb *urb);
68static void kobil_write_callback(struct urb *purb); 68static void kobil_write_int_callback(struct urb *urb);
69static void kobil_set_termios(struct tty_struct *tty, 69static 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);
71static void kobil_init_termios(struct tty_struct *tty); 71static 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
104static struct usb_serial_driver * const serial_drivers[] = { 105static struct usb_serial_driver * const serial_drivers[] = {
@@ -106,7 +107,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
106}; 107};
107 108
108struct kobil_private { 109struct 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
117static int kobil_port_probe(struct usb_serial_port *port) 117static 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)
302static void kobil_close(struct usb_serial_port *port) 257static 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
339static void kobil_write_callback(struct urb *purb) 289static 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