00001
00034 #ifndef USB_UDC_LIB_H_INCLUDED
00035 #define USB_UDC_LIB_H_INCLUDED
00036
00037 #include <slist.h>
00038 #include <string.h>
00039 #include <types.h>
00040 #include <usb/request.h>
00041
00042 struct udc;
00043 struct usb_setup_req;
00044
00058
00072 extern status_t udc_enter_test_mode(struct udc *udc, unsigned int mode);
00073
00087 extern status_t udc_lib_process_setup_request(struct udc *udc,
00088 struct usb_setup_req *req);
00089
00091
00103
00107 struct udc_fifo {
00108 size_t buf_offset;
00109 size_t size;
00110
00116 bool send_zlp;
00117 };
00118
00125 static inline void udc_fifo_init(struct udc_fifo *fifo, size_t aperture_size)
00126 {
00127 fifo->buf_offset = 0;
00128 fifo->size = aperture_size;
00129 fifo->send_zlp = false;
00130 }
00131
00143 static inline bool udc_fifo_zlp_is_pending(struct udc_fifo *fifo,
00144 struct usb_request *req)
00145 {
00146 return fifo->send_zlp;
00147 }
00148
00156 static inline void udc_fifo_zlp_clear_pending(struct udc_fifo *fifo,
00157 struct usb_request *req)
00158 {
00159 fifo->send_zlp = false;
00160 }
00161
00183 static inline int udc_fifo_write_data(void *dest, struct udc_fifo *fifo,
00184 struct slist *done_list, struct usb_request *req)
00185 {
00186 struct buffer *buf;
00187 unsigned int bytes_written;
00188 unsigned int buf_offset;
00189 unsigned int fifo_size;
00190
00191 buf = buf_list_pop_head(&req->buf_list);
00192 buf_offset = fifo->buf_offset;
00193 fifo_size = fifo->size;
00194
00195 for (bytes_written = 0; bytes_written < fifo_size; ) {
00196 unsigned int nbytes;
00197 unsigned int buf_len;
00198
00199 buf_len = buf->len;
00200 nbytes = min_u(fifo_size - bytes_written, buf_len - buf_offset);
00201 dbg_verbose("udc write: dst %p src %p off %u nbytes %u\n",
00202 (char *)dest + bytes_written,
00203 buf->addr.ptr, buf_offset, nbytes);
00204 memcpy((char *)dest + bytes_written,
00205 (const char *)buf->addr.ptr + buf_offset,
00206 nbytes);
00207
00208 buf_offset += nbytes;
00209 bytes_written += nbytes;
00210
00211 if (buf_offset == buf_len) {
00212 buf_offset = 0;
00213 slist_insert_tail(done_list, &buf->node);
00214 if (slist_is_empty(&req->buf_list)) {
00215 if (bytes_written == fifo_size
00216 && test_bit(USB_REQ_SHORT_PKT,
00217 &req->flags))
00218 fifo->send_zlp = true;
00219 goto done;
00220 }
00221 buf = buf_list_pop_head(&req->buf_list);
00222 }
00223 }
00224
00225
00226 slist_insert_head(&req->buf_list, &buf->node);
00227
00228 done:
00229 fifo->buf_offset = buf_offset;
00230
00231 return bytes_written;
00232 }
00233
00257 static inline unsigned int udc_fifo_read_data(const void *src,
00258 struct udc_fifo *fifo, unsigned int fifo_nbytes,
00259 struct slist *done_bufs, struct usb_request *req)
00260 {
00261 struct buffer *buf;
00262 unsigned int bytes_read;
00263 unsigned int buf_offset;
00264
00265 assert(fifo_nbytes <= fifo->size);
00266
00267 buf = buf_list_pop_head(&req->buf_list);
00268 buf_offset = fifo->buf_offset;
00269
00270 for (bytes_read = 0; bytes_read < fifo_nbytes; ) {
00271 unsigned int nbytes;
00272 unsigned int buf_len;
00273
00274 buf_len = buf->len;
00275 nbytes = min_u(fifo_nbytes - bytes_read, buf_len - buf_offset);
00276 dbg_verbose("udc read: dst %p src %p off %u nbytes %u\n",
00277 buf->addr.ptr, (const char *)src + bytes_read,
00278 buf_offset, nbytes);
00279 memcpy((char *)buf->addr.ptr + buf_offset,
00280 (const char *)src + bytes_read, nbytes);
00281
00282 buf_offset += nbytes;
00283 bytes_read += nbytes;
00284
00285 if (buf_offset == buf_len) {
00286 buf_offset = 0;
00287 slist_insert_tail(done_bufs, &buf->node);
00288 if (slist_is_empty(&req->buf_list))
00289 goto done;
00290 buf = buf_list_pop_head(&req->buf_list);
00291 }
00292 }
00293
00294
00295 slist_insert_head(&req->buf_list, &buf->node);
00296
00297 done:
00298 fifo->buf_offset = buf_offset;
00299
00300 return bytes_read;
00301 }
00302
00304
00305
00306 #endif