diff options
author | Johan Hovold <jhovold@gmail.com> | 2010-03-17 18:06:08 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:35 -0400 |
commit | eaa3bcb06aed1ac1d6d9e3edd3b5f72ea57a6ac0 (patch) | |
tree | a55b216df6a5977ab8d502df44397ef7ebbb11bc /drivers/usb/serial/generic.c | |
parent | 25d514ca227e1ac81d0906a4ccf2aa171f50a600 (diff) |
USB: serial: generalise write buffer preparation
Generalise write buffer preparation.
This allows for drivers to manipulate (e.g. add headers) to bulk out
data before it is sent.
This adds a new function pointer to usb_serial_driver:
int (*prepare_write_buffer)(struct usb_serial_port *port,
void **dest, size_t size, const void *src, size_t count);
The function is generic and can be used with either kfifo-based or
multi-urb writes:
If *dest is NULL the implementation should allocate dest.
If src is NULL the implementation should use the port write fifo.
If not set, a generic implementation is used which simply uses memcpy or
kfifo_out.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ad4823bbfa19..1a134f9c64f3 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -167,12 +167,35 @@ void usb_serial_generic_close(struct usb_serial_port *port) | |||
167 | } | 167 | } |
168 | EXPORT_SYMBOL_GPL(usb_serial_generic_close); | 168 | EXPORT_SYMBOL_GPL(usb_serial_generic_close); |
169 | 169 | ||
170 | int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, | ||
171 | void **dest, size_t size, const void *src, size_t count) | ||
172 | { | ||
173 | if (!*dest) { | ||
174 | size = count; | ||
175 | *dest = kmalloc(count, GFP_ATOMIC); | ||
176 | if (!*dest) { | ||
177 | dev_err(&port->dev, "%s - could not allocate buffer\n", | ||
178 | __func__); | ||
179 | return -ENOMEM; | ||
180 | } | ||
181 | } | ||
182 | if (src) { | ||
183 | count = size; | ||
184 | memcpy(*dest, src, size); | ||
185 | } else { | ||
186 | count = kfifo_out_locked(&port->write_fifo, *dest, size, | ||
187 | &port->lock); | ||
188 | } | ||
189 | return count; | ||
190 | } | ||
191 | EXPORT_SYMBOL_GPL(usb_serial_generic_prepare_write_buffer); | ||
192 | |||
170 | static int usb_serial_multi_urb_write(struct tty_struct *tty, | 193 | static int usb_serial_multi_urb_write(struct tty_struct *tty, |
171 | struct usb_serial_port *port, const unsigned char *buf, int count) | 194 | struct usb_serial_port *port, const unsigned char *buf, int count) |
172 | { | 195 | { |
173 | unsigned long flags; | 196 | unsigned long flags; |
174 | struct urb *urb; | 197 | struct urb *urb; |
175 | unsigned char *buffer; | 198 | void *buffer; |
176 | int status; | 199 | int status; |
177 | 200 | ||
178 | spin_lock_irqsave(&port->lock, flags); | 201 | spin_lock_irqsave(&port->lock, flags); |
@@ -191,16 +214,14 @@ static int usb_serial_multi_urb_write(struct tty_struct *tty, | |||
191 | goto err_urb; | 214 | goto err_urb; |
192 | } | 215 | } |
193 | 216 | ||
217 | buffer = NULL; | ||
194 | count = min_t(int, count, PAGE_SIZE); | 218 | count = min_t(int, count, PAGE_SIZE); |
195 | buffer = kmalloc(count, GFP_ATOMIC); | 219 | count = port->serial->type->prepare_write_buffer(port, &buffer, 0, |
196 | if (!buffer) { | 220 | buf, count); |
197 | dev_err(&port->dev, "%s - could not allocate buffer\n", | 221 | if (count < 0) { |
198 | __func__); | 222 | status = count; |
199 | status = -ENOMEM; | ||
200 | goto err_buf; | 223 | goto err_buf; |
201 | } | 224 | } |
202 | |||
203 | memcpy(buffer, buf, count); | ||
204 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); | 225 | usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); |
205 | usb_fill_bulk_urb(urb, port->serial->dev, | 226 | usb_fill_bulk_urb(urb, port->serial->dev, |
206 | usb_sndbulkpipe(port->serial->dev, | 227 | usb_sndbulkpipe(port->serial->dev, |
@@ -242,7 +263,6 @@ err_urb: | |||
242 | */ | 263 | */ |
243 | static int usb_serial_generic_write_start(struct usb_serial_port *port) | 264 | static int usb_serial_generic_write_start(struct usb_serial_port *port) |
244 | { | 265 | { |
245 | unsigned char *data; | ||
246 | int result; | 266 | int result; |
247 | int count; | 267 | int count; |
248 | unsigned long flags; | 268 | unsigned long flags; |
@@ -255,10 +275,11 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port) | |||
255 | port->write_urb_busy = 1; | 275 | port->write_urb_busy = 1; |
256 | spin_unlock_irqrestore(&port->lock, flags); | 276 | spin_unlock_irqrestore(&port->lock, flags); |
257 | 277 | ||
258 | data = port->write_urb->transfer_buffer; | 278 | count = port->serial->type->prepare_write_buffer(port, |
259 | count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock); | 279 | &port->write_urb->transfer_buffer, |
260 | usb_serial_debug_data(debug, &port->dev, __func__, count, data); | 280 | port->bulk_out_size, NULL, 0); |
261 | 281 | usb_serial_debug_data(debug, &port->dev, __func__, | |
282 | count, port->write_urb->transfer_buffer); | ||
262 | port->write_urb->transfer_buffer_length = count; | 283 | port->write_urb->transfer_buffer_length = count; |
263 | 284 | ||
264 | /* send the data out the bulk port */ | 285 | /* send the data out the bulk port */ |