source: mainline/uspace/drv/ohci/batch.c@ e42dd32

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e42dd32 was e42dd32, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

OCHI structures fixed, setup control transfer

  • Property mode set to 100644
File size: 9.8 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup drvusbohci
29 * @{
30 */
31/** @file
32 * @brief OHCI driver USB transaction structure
33 */
34#include <errno.h>
35#include <str_error.h>
36
37#include <usb/usb.h>
38#include <usb/debug.h>
39
40#include "batch.h"
41#include "utils/malloc32.h"
42#include "hw_struct/endpoint_descriptor.h"
43#include "hw_struct/transfer_descriptor.h"
44
45typedef struct ohci_batch {
46 ed_t *ed;
47 td_t *tds;
48 size_t td_count;
49} ohci_batch_t;
50
51static void batch_control(usb_transfer_batch_t *instance,
52 usb_direction_t data_dir, usb_direction_t status_dir);
53static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);
54static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);
55
56#define DEFAULT_ERROR_COUNT 3
57usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
58 char *buffer, size_t buffer_size, char* setup_buffer, size_t setup_size,
59 usbhc_iface_transfer_in_callback_t func_in,
60 usbhc_iface_transfer_out_callback_t func_out, void *arg)
61{
62#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
63 if (ptr == NULL) { \
64 usb_log_error(message); \
65 if (instance) { \
66 batch_dispose(instance); \
67 } \
68 return NULL; \
69 } else (void)0
70
71 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
72 CHECK_NULL_DISPOSE_RETURN(instance,
73 "Failed to allocate batch instance.\n");
74 usb_target_t target =
75 { .address = ep->address, .endpoint = ep->endpoint };
76 usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed,
77 ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size,
78 func_in, func_out, arg, fun, ep, NULL);
79
80 ohci_batch_t *data = malloc(sizeof(ohci_batch_t));
81 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
82 bzero(data, sizeof(ohci_batch_t));
83 instance->private_data = data;
84
85 /* we needs + 1 transfer descriptor as the last one won't be executed */
86 data->td_count = 1 +
87 ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
88 if (ep->transfer_type == USB_TRANSFER_CONTROL) {
89 data->td_count += 2;
90 }
91
92 data->tds = malloc32(sizeof(td_t) * data->td_count);
93 CHECK_NULL_DISPOSE_RETURN(data->tds,
94 "Failed to allocate transfer descriptors.\n");
95 bzero(data->tds, sizeof(td_t) * data->td_count);
96
97 data->ed = malloc32(sizeof(ed_t));
98 CHECK_NULL_DISPOSE_RETURN(data->ed,
99 "Failed to allocate endpoint descriptor.\n");
100
101 if (buffer_size > 0) {
102 instance->transport_buffer = malloc32(buffer_size);
103 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
104 "Failed to allocate device accessible buffer.\n");
105 }
106
107 if (setup_size > 0) {
108 instance->setup_buffer = malloc32(setup_size);
109 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
110 "Failed to allocate device accessible setup buffer.\n");
111 memcpy(instance->setup_buffer, setup_buffer, setup_size);
112 }
113
114 return instance;
115}
116/*----------------------------------------------------------------------------*/
117void batch_dispose(usb_transfer_batch_t *instance)
118{
119 assert(instance);
120 free32(instance->transport_buffer);
121 free32(instance->setup_buffer);
122 free(instance);
123}
124/*----------------------------------------------------------------------------*/
125bool batch_is_complete(usb_transfer_batch_t *instance)
126{
127 // TODO: implement
128 return false;
129}
130/*----------------------------------------------------------------------------*/
131void batch_control_write(usb_transfer_batch_t *instance)
132{
133 assert(instance);
134 /* We are data out, we are supposed to provide data */
135 memcpy(instance->transport_buffer, instance->buffer,
136 instance->buffer_size);
137 instance->next_step = batch_call_out_and_dispose;
138 batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
139 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
140}
141/*----------------------------------------------------------------------------*/
142void batch_control_read(usb_transfer_batch_t *instance)
143{
144 assert(instance);
145 instance->next_step = batch_call_in_and_dispose;
146 batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
147 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
148}
149/*----------------------------------------------------------------------------*/
150void batch_interrupt_in(usb_transfer_batch_t *instance)
151{
152 assert(instance);
153 assert(instance->direction == USB_DIRECTION_IN);
154 instance->next_step = batch_call_in_and_dispose;
155 /* TODO: implement */
156 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
157}
158/*----------------------------------------------------------------------------*/
159void batch_interrupt_out(usb_transfer_batch_t *instance)
160{
161 assert(instance);
162 assert(instance->direction == USB_DIRECTION_OUT);
163 /* We are data out, we are supposed to provide data */
164 memcpy(instance->transport_buffer, instance->buffer,
165 instance->buffer_size);
166 instance->next_step = batch_call_out_and_dispose;
167 /* TODO: implement */
168 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
169}
170/*----------------------------------------------------------------------------*/
171void batch_bulk_in(usb_transfer_batch_t *instance)
172{
173 assert(instance);
174 instance->direction = USB_DIRECTION_IN;
175 instance->next_step = batch_call_in_and_dispose;
176 /* TODO: implement */
177 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
178}
179/*----------------------------------------------------------------------------*/
180void batch_bulk_out(usb_transfer_batch_t *instance)
181{
182 assert(instance);
183 instance->direction = USB_DIRECTION_IN;
184 instance->next_step = batch_call_in_and_dispose;
185 /* TODO: implement */
186 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
187}
188/*----------------------------------------------------------------------------*/
189ed_t * batch_ed(usb_transfer_batch_t *instance)
190{
191 assert(instance);
192 ohci_batch_t *data = instance->private_data;
193 assert(data);
194 return data->ed;
195}
196/*----------------------------------------------------------------------------*/
197void batch_control(usb_transfer_batch_t *instance,
198 usb_direction_t data_dir, usb_direction_t status_dir)
199{
200 assert(instance);
201 ohci_batch_t *data = instance->private_data;
202 assert(data);
203 ed_init(data->ed, instance->ep);
204 ed_add_tds(data->ed, &data->tds[0], &data->tds[data->td_count - 1]);
205 usb_log_debug("Created ED: %x:%x:%x:%x.\n", data->ed->status,
206 data->ed->td_tail, data->ed->td_head, data->ed->next);
207 int toggle = 0;
208 /* setup stage */
209 td_init(&data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
210 instance->setup_size, toggle);
211 td_set_next(&data->tds[0], &data->tds[1]);
212 usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0].status,
213 data->tds[0].cbp, data->tds[0].next, data->tds[0].be);
214
215 /* data stage */
216 size_t td_current = 1;
217 size_t remain_size = instance->buffer_size;
218 char *transfer_buffer = instance->transport_buffer;
219 while (remain_size > 0) {
220 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
221 OHCI_TD_MAX_TRANSFER : remain_size;
222 toggle = 1 - toggle;
223
224 td_init(&data->tds[td_current], data_dir, transfer_buffer,
225 transfer_size, toggle);
226 td_set_next(&data->tds[td_current], &data->tds[td_current + 1]);
227 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
228 data->tds[td_current].status, data->tds[td_current].cbp,
229 data->tds[td_current].next, data->tds[td_current].be);
230
231 transfer_buffer += transfer_size;
232 remain_size -= transfer_size;
233 assert(td_current < data->td_count - 2);
234 ++td_current;
235 }
236
237 /* status stage */
238 assert(td_current == data->td_count - 2);
239 td_init(&data->tds[td_current], status_dir, NULL, 0, 1);
240 usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n",
241 data->tds[td_current].status, data->tds[td_current].cbp,
242 data->tds[td_current].next, data->tds[td_current].be);
243}
244/*----------------------------------------------------------------------------*/
245/** Helper function calls callback and correctly disposes of batch structure.
246 *
247 * @param[in] instance Batch structure to use.
248 */
249void batch_call_in_and_dispose(usb_transfer_batch_t *instance)
250{
251 assert(instance);
252 usb_transfer_batch_call_in(instance);
253 batch_dispose(instance);
254}
255/*----------------------------------------------------------------------------*/
256/** Helper function calls callback and correctly disposes of batch structure.
257 *
258 * @param[in] instance Batch structure to use.
259 */
260void batch_call_out_and_dispose(usb_transfer_batch_t *instance)
261{
262 assert(instance);
263 usb_transfer_batch_call_out(instance);
264 batch_dispose(instance);
265}
266/**
267 * @}
268 */
Note: See TracBrowser for help on using the repository browser.