In line6_version_request_async() we set up an async message but we free
the buffer with the version in it before the message has been sent.

I've introduced a new function line6_async_request_sent_free_buffer()
which frees the data after we are done with it.  I've added a "free"
parameter to the line6_send_raw_message_async() functions so that they
know if they have to free the msg->buffer or not at the end.

Reported-by: Stefan Hajnoczi <[email protected]>
Signed-off-by: Dan Carpenter <[email protected]>

diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index 1dd768c2..918d19e 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -205,7 +205,7 @@ extern int line6_send_program(struct usb_line6 *line6, u8 
value);
 extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
                                  int size);
 extern int line6_send_raw_message_async(struct usb_line6 *line6,
-                                       const char *buffer, int size);
+                                       const char *buffer, int size, int free);
 extern int line6_send_sysex_message(struct usb_line6 *line6,
                                    const char *buffer, int size);
 extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
index 4fca58f..f97512d 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -47,7 +47,7 @@ static void variax_activate_async(struct usb_line6_variax 
*variax, int a)
 {
        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
        line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
-                                    sizeof(variax_activate));
+                                    sizeof(variax_activate), 0);
 }
 
 /*
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 8a5d89e..884e0d8 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -110,7 +110,7 @@ struct message {
 */
 static void line6_data_received(struct urb *urb);
 static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb);
+                                            struct urb *urb, int free);
 
 /*
        Start to listen on endpoint.
@@ -219,24 +219,42 @@ static void line6_async_request_sent(struct urb *urb)
                usb_free_urb(urb);
                kfree(msg);
        } else
-               line6_send_raw_message_async_part(msg, urb);
+               line6_send_raw_message_async_part(msg, urb, 0);
+}
+
+static void line6_async_request_sent_free_buffer(struct urb *urb)
+{
+       struct message *msg = (struct message *)urb->context;
+
+       if (msg->done >= msg->size) {
+               usb_free_urb(urb);
+               kfree(msg->buffer);
+               kfree(msg);
+       } else
+               line6_send_raw_message_async_part(msg, urb, 1);
 }
 
 /*
        Asynchronously send part of a raw message.
 */
 static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb)
+                                            struct urb *urb, int free)
 {
        int retval;
        struct usb_line6 *line6 = msg->line6;
        int done = msg->done;
        int bytes = min(msg->size - done, line6->max_packet_size);
+       usb_complete_t complete_fn;
+
+       if (free)
+               complete_fn = line6_async_request_sent_free_buffer;
+       else
+               complete_fn = line6_async_request_sent;
 
        usb_fill_int_urb(urb, line6->usbdev,
                         usb_sndintpipe(line6->usbdev, line6->ep_control_write),
-                        (char *)msg->buffer + done, bytes,
-                        line6_async_request_sent, msg, line6->interval);
+                        (char *)msg->buffer + done, bytes, complete_fn, msg,
+                        line6->interval);
 
        msg->done += bytes;
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -267,7 +285,7 @@ void line6_start_timer(struct timer_list *timer, unsigned 
int msecs,
        Asynchronously send raw message.
 */
 int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
-                                int size)
+                                int size, int free)
 {
        struct message *msg;
        struct urb *urb;
@@ -296,7 +314,7 @@ int line6_send_raw_message_async(struct usb_line6 *line6, 
const char *buffer,
        msg->done = 0;
 
        /* start sending: */
-       return line6_send_raw_message_async_part(msg, urb);
+       return line6_send_raw_message_async_part(msg, urb, free);
 }
 
 /*
@@ -316,8 +334,7 @@ int line6_version_request_async(struct usb_line6 *line6)
        memcpy(buffer, line6_request_version, sizeof(line6_request_version));
 
        retval = line6_send_raw_message_async(line6, buffer,
-                                             sizeof(line6_request_version));
-       kfree(buffer);
+                                             sizeof(line6_request_version), 1);
        return retval;
 }
 
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel

Reply via email to