Merge branch 'for-2.6.39' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / drivers / staging / usbip / vhci_tx.c
1 /*
2  * Copyright (C) 2003-2008 Takahiro Hirofuchi
3  *
4  * This is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17  * USA.
18  */
19
20 #include <linux/slab.h>
21 #include <linux/kthread.h>
22
23 #include "usbip_common.h"
24 #include "vhci.h"
25
26
27 static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
28 {
29         struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
30         struct vhci_device *vdev = priv->vdev;
31
32         usbip_dbg_vhci_tx("URB, local devnum %u, remote devid %u\n",
33                                 usb_pipedevice(urb->pipe), vdev->devid);
34
35         pdup->base.command = USBIP_CMD_SUBMIT;
36         pdup->base.seqnum  = priv->seqnum;
37         pdup->base.devid   = vdev->devid;
38         if (usb_pipein(urb->pipe))
39                 pdup->base.direction = USBIP_DIR_IN;
40         else
41                 pdup->base.direction = USBIP_DIR_OUT;
42         pdup->base.ep      = usb_pipeendpoint(urb->pipe);
43
44         usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1);
45
46         if (urb->setup_packet)
47                 memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
48 }
49
50 static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
51 {
52         unsigned long flags;
53         struct vhci_priv *priv, *tmp;
54
55         spin_lock_irqsave(&vdev->priv_lock, flags);
56
57         list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
58                 list_move_tail(&priv->list, &vdev->priv_rx);
59                 spin_unlock_irqrestore(&vdev->priv_lock, flags);
60                 return priv;
61         }
62
63         spin_unlock_irqrestore(&vdev->priv_lock, flags);
64
65         return NULL;
66 }
67
68
69
70 static int vhci_send_cmd_submit(struct vhci_device *vdev)
71 {
72         struct vhci_priv *priv = NULL;
73
74         struct msghdr msg;
75         struct kvec iov[3];
76         size_t txsize;
77
78         size_t total_size = 0;
79
80         while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
81                 int ret;
82                 struct urb *urb = priv->urb;
83                 struct usbip_header pdu_header;
84                 void *iso_buffer = NULL;
85
86                 txsize = 0;
87                 memset(&pdu_header, 0, sizeof(pdu_header));
88                 memset(&msg, 0, sizeof(msg));
89                 memset(&iov, 0, sizeof(iov));
90
91                 usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
92
93
94                 /* 1. setup usbip_header */
95                 setup_cmd_submit_pdu(&pdu_header, urb);
96                 usbip_header_correct_endian(&pdu_header, 1);
97
98                 iov[0].iov_base = &pdu_header;
99                 iov[0].iov_len  = sizeof(pdu_header);
100                 txsize += sizeof(pdu_header);
101
102                 /* 2. setup transfer buffer */
103                 if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) {
104                         iov[1].iov_base = urb->transfer_buffer;
105                         iov[1].iov_len  = urb->transfer_buffer_length;
106                         txsize += urb->transfer_buffer_length;
107                 }
108
109                 /* 3. setup iso_packet_descriptor */
110                 if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
111                         ssize_t len = 0;
112
113                         iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
114                         if (!iso_buffer) {
115                                 usbip_event_add(&vdev->ud,
116                                                 SDEV_EVENT_ERROR_MALLOC);
117                                 return -1;
118                         }
119
120                         iov[2].iov_base = iso_buffer;
121                         iov[2].iov_len  = len;
122                         txsize += len;
123                 }
124
125                 ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
126                 if (ret != txsize) {
127                         usbip_uerr("sendmsg failed!, retval %d for %zd\n", ret,
128                                                                         txsize);
129                         kfree(iso_buffer);
130                         usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
131                         return -1;
132                 }
133
134                 kfree(iso_buffer);
135                 usbip_dbg_vhci_tx("send txdata\n");
136
137                 total_size += txsize;
138         }
139
140         return total_size;
141 }
142
143
144 /*-------------------------------------------------------------------------*/
145
146 static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
147 {
148         unsigned long flags;
149         struct vhci_unlink *unlink, *tmp;
150
151         spin_lock_irqsave(&vdev->priv_lock, flags);
152
153         list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
154                 list_move_tail(&unlink->list, &vdev->unlink_rx);
155                 spin_unlock_irqrestore(&vdev->priv_lock, flags);
156                 return unlink;
157         }
158
159         spin_unlock_irqrestore(&vdev->priv_lock, flags);
160
161         return NULL;
162 }
163
164 static int vhci_send_cmd_unlink(struct vhci_device *vdev)
165 {
166         struct vhci_unlink *unlink = NULL;
167
168         struct msghdr msg;
169         struct kvec iov[3];
170         size_t txsize;
171
172         size_t total_size = 0;
173
174         while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
175                 int ret;
176                 struct usbip_header pdu_header;
177
178                 txsize = 0;
179                 memset(&pdu_header, 0, sizeof(pdu_header));
180                 memset(&msg, 0, sizeof(msg));
181                 memset(&iov, 0, sizeof(iov));
182
183                 usbip_dbg_vhci_tx("setup cmd unlink, %lu\n", unlink->seqnum);
184
185
186                 /* 1. setup usbip_header */
187                 pdu_header.base.command = USBIP_CMD_UNLINK;
188                 pdu_header.base.seqnum  = unlink->seqnum;
189                 pdu_header.base.devid   = vdev->devid;
190                 pdu_header.base.ep      = 0;
191                 pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum;
192
193                 usbip_header_correct_endian(&pdu_header, 1);
194
195                 iov[0].iov_base = &pdu_header;
196                 iov[0].iov_len  = sizeof(pdu_header);
197                 txsize += sizeof(pdu_header);
198
199                 ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
200                 if (ret != txsize) {
201                         usbip_uerr("sendmsg failed!, retval %d for %zd\n", ret,
202                                                                         txsize);
203                         usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
204                         return -1;
205                 }
206
207
208                 usbip_dbg_vhci_tx("send txdata\n");
209
210                 total_size += txsize;
211         }
212
213         return total_size;
214 }
215
216
217 /*-------------------------------------------------------------------------*/
218
219 int vhci_tx_loop(void *data)
220 {
221         struct usbip_device *ud = data;
222         struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
223
224         while (!kthread_should_stop()) {
225                 if (vhci_send_cmd_submit(vdev) < 0)
226                         break;
227
228                 if (vhci_send_cmd_unlink(vdev) < 0)
229                         break;
230
231                 wait_event_interruptible(vdev->waitq_tx,
232                                 (!list_empty(&vdev->priv_tx) ||
233                                  !list_empty(&vdev->unlink_tx) ||
234                                  kthread_should_stop()));
235
236                 usbip_dbg_vhci_tx("pending urbs ?, now wake up\n");
237         }
238
239         return 0;
240 }