aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/u_serial.c
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2008-08-06 21:49:57 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-13 20:32:57 -0400
commit1f1ba11b64947051fc32aa15fcccef6463b433f7 (patch)
tree546d99300dc56f4fe744385263eb3864e843f83e /drivers/usb/gadget/u_serial.c
parent630c7aa80152881980e45c11584f22476f71959b (diff)
usb gadget: issue notifications from ACM function
Update the CDC-ACM gadget code to support the peripheral-to-host notifications when the tty is opened or closed, or issues a BREAK. The serial framework code calls new generic hooks; right now only CDC-ACM uses those hooks. This resolves several REVISIT comments in the code. (Based on a patch from Felipe Balbi.) Note that this doesn't expose USB_CDC_CAP_BRK to the host, since this code still rejects USB_CDC_REQ_SEND_BREAK control requests for host-to-peripheral BREAK signaling (received via /dev/ttyGS*). Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Felipe Balbi <felipe.balbi@nokia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/u_serial.c')
-rw-r--r--drivers/usb/gadget/u_serial.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6641efa55639..53d59287f2bc 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -60,7 +60,8 @@
60 * tty_struct links to the tty/filesystem framework 60 * tty_struct links to the tty/filesystem framework
61 * 61 *
62 * gserial <---> gs_port ... links will be null when the USB link is 62 * gserial <---> gs_port ... links will be null when the USB link is
63 * inactive; managed by gserial_{connect,disconnect}(). 63 * inactive; managed by gserial_{connect,disconnect}(). each gserial
64 * instance can wrap its own USB control protocol.
64 * gserial->ioport == usb_ep->driver_data ... gs_port 65 * gserial->ioport == usb_ep->driver_data ... gs_port
65 * gs_port->port_usb ... gserial 66 * gs_port->port_usb ... gserial
66 * 67 *
@@ -181,7 +182,7 @@ static void gs_buf_clear(struct gs_buf *gb)
181/* 182/*
182 * gs_buf_data_avail 183 * gs_buf_data_avail
183 * 184 *
184 * Return the number of bytes of data available in the circular 185 * Return the number of bytes of data written into the circular
185 * buffer. 186 * buffer.
186 */ 187 */
187static unsigned gs_buf_data_avail(struct gs_buf *gb) 188static unsigned gs_buf_data_avail(struct gs_buf *gb)
@@ -282,7 +283,7 @@ gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
282 * Allocate a usb_request and its buffer. Returns a pointer to the 283 * Allocate a usb_request and its buffer. Returns a pointer to the
283 * usb_request or NULL if there is an error. 284 * usb_request or NULL if there is an error.
284 */ 285 */
285static struct usb_request * 286struct usb_request *
286gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) 287gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
287{ 288{
288 struct usb_request *req; 289 struct usb_request *req;
@@ -306,7 +307,7 @@ gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
306 * 307 *
307 * Free a usb_request and its buffer. 308 * Free a usb_request and its buffer.
308 */ 309 */
309static void gs_free_req(struct usb_ep *ep, struct usb_request *req) 310void gs_free_req(struct usb_ep *ep, struct usb_request *req)
310{ 311{
311 kfree(req->buf); 312 kfree(req->buf);
312 usb_ep_free_request(ep, req); 313 usb_ep_free_request(ep, req);
@@ -788,10 +789,13 @@ static int gs_open(struct tty_struct *tty, struct file *file)
788 789
789 /* if connected, start the I/O stream */ 790 /* if connected, start the I/O stream */
790 if (port->port_usb) { 791 if (port->port_usb) {
792 struct gserial *gser = port->port_usb;
793
791 pr_debug("gs_open: start ttyGS%d\n", port->port_num); 794 pr_debug("gs_open: start ttyGS%d\n", port->port_num);
792 gs_start_io(port); 795 gs_start_io(port);
793 796
794 /* REVISIT for ACM, issue "network connected" event */ 797 if (gser->connect)
798 gser->connect(gser);
795 } 799 }
796 800
797 pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); 801 pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
@@ -818,6 +822,7 @@ static int gs_writes_finished(struct gs_port *p)
818static void gs_close(struct tty_struct *tty, struct file *file) 822static void gs_close(struct tty_struct *tty, struct file *file)
819{ 823{
820 struct gs_port *port = tty->driver_data; 824 struct gs_port *port = tty->driver_data;
825 struct gserial *gser;
821 826
822 spin_lock_irq(&port->port_lock); 827 spin_lock_irq(&port->port_lock);
823 828
@@ -837,26 +842,27 @@ static void gs_close(struct tty_struct *tty, struct file *file)
837 port->openclose = true; 842 port->openclose = true;
838 port->open_count = 0; 843 port->open_count = 0;
839 844
840 if (port->port_usb) 845 gser = port->port_usb;
841 /* REVISIT for ACM, issue "network disconnected" event */; 846 if (gser && gser->disconnect)
847 gser->disconnect(gser);
842 848
843 /* wait for circular write buffer to drain, disconnect, or at 849 /* wait for circular write buffer to drain, disconnect, or at
844 * most GS_CLOSE_TIMEOUT seconds; then discard the rest 850 * most GS_CLOSE_TIMEOUT seconds; then discard the rest
845 */ 851 */
846 if (gs_buf_data_avail(&port->port_write_buf) > 0 852 if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
847 && port->port_usb) {
848 spin_unlock_irq(&port->port_lock); 853 spin_unlock_irq(&port->port_lock);
849 wait_event_interruptible_timeout(port->drain_wait, 854 wait_event_interruptible_timeout(port->drain_wait,
850 gs_writes_finished(port), 855 gs_writes_finished(port),
851 GS_CLOSE_TIMEOUT * HZ); 856 GS_CLOSE_TIMEOUT * HZ);
852 spin_lock_irq(&port->port_lock); 857 spin_lock_irq(&port->port_lock);
858 gser = port->port_usb;
853 } 859 }
854 860
855 /* Iff we're disconnected, there can be no I/O in flight so it's 861 /* Iff we're disconnected, there can be no I/O in flight so it's
856 * ok to free the circular buffer; else just scrub it. And don't 862 * ok to free the circular buffer; else just scrub it. And don't
857 * let the push tasklet fire again until we're re-opened. 863 * let the push tasklet fire again until we're re-opened.
858 */ 864 */
859 if (port->port_usb == NULL) 865 if (gser == NULL)
860 gs_buf_free(&port->port_write_buf); 866 gs_buf_free(&port->port_write_buf);
861 else 867 else
862 gs_buf_clear(&port->port_write_buf); 868 gs_buf_clear(&port->port_write_buf);
@@ -974,6 +980,24 @@ static void gs_unthrottle(struct tty_struct *tty)
974 spin_unlock_irqrestore(&port->port_lock, flags); 980 spin_unlock_irqrestore(&port->port_lock, flags);
975} 981}
976 982
983static int gs_break_ctl(struct tty_struct *tty, int duration)
984{
985 struct gs_port *port = tty->driver_data;
986 int status = 0;
987 struct gserial *gser;
988
989 pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n",
990 port->port_num, duration);
991
992 spin_lock_irq(&port->port_lock);
993 gser = port->port_usb;
994 if (gser && gser->send_break)
995 status = gser->send_break(gser, duration);
996 spin_unlock_irq(&port->port_lock);
997
998 return status;
999}
1000
977static const struct tty_operations gs_tty_ops = { 1001static const struct tty_operations gs_tty_ops = {
978 .open = gs_open, 1002 .open = gs_open,
979 .close = gs_close, 1003 .close = gs_close,
@@ -983,6 +1007,7 @@ static const struct tty_operations gs_tty_ops = {
983 .write_room = gs_write_room, 1007 .write_room = gs_write_room,
984 .chars_in_buffer = gs_chars_in_buffer, 1008 .chars_in_buffer = gs_chars_in_buffer,
985 .unthrottle = gs_unthrottle, 1009 .unthrottle = gs_unthrottle,
1010 .break_ctl = gs_break_ctl,
986}; 1011};
987 1012
988/*-------------------------------------------------------------------------*/ 1013/*-------------------------------------------------------------------------*/
@@ -1230,14 +1255,17 @@ int gserial_connect(struct gserial *gser, u8 port_num)
1230 1255
1231 /* REVISIT if waiting on "carrier detect", signal. */ 1256 /* REVISIT if waiting on "carrier detect", signal. */
1232 1257
1233 /* REVISIT for ACM, issue "network connection" status notification: 1258 /* if it's already open, start I/O ... and notify the serial
1234 * connected if open_count, else disconnected. 1259 * protocol about open/close status (connect/disconnect).
1235 */ 1260 */
1236
1237 /* if it's already open, start I/O */
1238 if (port->open_count) { 1261 if (port->open_count) {
1239 pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); 1262 pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
1240 gs_start_io(port); 1263 gs_start_io(port);
1264 if (gser->connect)
1265 gser->connect(gser);
1266 } else {
1267 if (gser->disconnect)
1268 gser->disconnect(gser);
1241 } 1269 }
1242 1270
1243 spin_unlock_irqrestore(&port->port_lock, flags); 1271 spin_unlock_irqrestore(&port->port_lock, flags);