1*06cb2463SMarkus Pfeiffer /* $FreeBSD: head/sys/dev/usb/usb_transfer.h 228056 2011-11-28 09:54:41Z hselasky $ */ 212bd3c8bSSascha Wildner /*- 312bd3c8bSSascha Wildner * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 412bd3c8bSSascha Wildner * 512bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without 612bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions 712bd3c8bSSascha Wildner * are met: 812bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright 912bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer. 1012bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the 1212bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution. 1312bd3c8bSSascha Wildner * 1412bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1512bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1612bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1712bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1812bd3c8bSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1912bd3c8bSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2012bd3c8bSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2112bd3c8bSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2212bd3c8bSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2312bd3c8bSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2412bd3c8bSSascha Wildner * SUCH DAMAGE. 2512bd3c8bSSascha Wildner */ 2612bd3c8bSSascha Wildner 2712bd3c8bSSascha Wildner #ifndef _USB_TRANSFER_H_ 2812bd3c8bSSascha Wildner #define _USB_TRANSFER_H_ 2912bd3c8bSSascha Wildner 3012bd3c8bSSascha Wildner /* 3112bd3c8bSSascha Wildner * Definition of internal USB transfer states: 3212bd3c8bSSascha Wildner * =========================================== 3312bd3c8bSSascha Wildner * 3412bd3c8bSSascha Wildner * The main reason there are many USB states is that we are allowed to 3512bd3c8bSSascha Wildner * cancel USB transfers, then start the USB transfer again and that 3612bd3c8bSSascha Wildner * this state transaction cannot always be done in a single atomic 3712bd3c8bSSascha Wildner * operation without blocking the calling thread. One reason for this 3812bd3c8bSSascha Wildner * is that the USB hardware sometimes needs to wait for DMA 3912bd3c8bSSascha Wildner * controllers to finish which is done asynchronously and grows the 4012bd3c8bSSascha Wildner * statemachine. 4112bd3c8bSSascha Wildner * 4212bd3c8bSSascha Wildner * When extending the following statemachine there are basically two 4312bd3c8bSSascha Wildner * things you should think about: Which states should be executed or 4412bd3c8bSSascha Wildner * modified in case of USB transfer stop and which states should be 4512bd3c8bSSascha Wildner * executed or modified in case of USB transfer start. Also respect 4612bd3c8bSSascha Wildner * the "can_cancel_immed" flag which basically tells if you can go 4712bd3c8bSSascha Wildner * directly from a wait state to the cancelling states. 4812bd3c8bSSascha Wildner */ 4912bd3c8bSSascha Wildner 5012bd3c8bSSascha Wildner enum { 5112bd3c8bSSascha Wildner /* XFER start execute state */ 5212bd3c8bSSascha Wildner 5312bd3c8bSSascha Wildner /* USB_ST_SETUP = 0 (already defined) */ 5412bd3c8bSSascha Wildner 5512bd3c8bSSascha Wildner /* XFER transferred execute state */ 5612bd3c8bSSascha Wildner 5712bd3c8bSSascha Wildner /* USB_ST_TRANSFERRED = 1 (already defined) */ 5812bd3c8bSSascha Wildner 5912bd3c8bSSascha Wildner /* XFER error execute state */ 6012bd3c8bSSascha Wildner 6112bd3c8bSSascha Wildner /* USB_ST_ERROR = 2 (already defined) */ 6212bd3c8bSSascha Wildner 6312bd3c8bSSascha Wildner /* XFER restart after error execute state */ 6412bd3c8bSSascha Wildner 6512bd3c8bSSascha Wildner USB_ST_RESTART = 8, 6612bd3c8bSSascha Wildner 6712bd3c8bSSascha Wildner /* XFER transfer idle state */ 6812bd3c8bSSascha Wildner 6912bd3c8bSSascha Wildner USB_ST_WAIT_SETUP, 7012bd3c8bSSascha Wildner 7112bd3c8bSSascha Wildner /* Other XFER execute states */ 7212bd3c8bSSascha Wildner 7312bd3c8bSSascha Wildner USB_ST_PIPE_OPEN = 16, 7412bd3c8bSSascha Wildner USB_ST_PIPE_OPEN_ERROR, 7512bd3c8bSSascha Wildner USB_ST_PIPE_OPEN_RESTART, 7612bd3c8bSSascha Wildner 7712bd3c8bSSascha Wildner USB_ST_BDMA_LOAD, 7812bd3c8bSSascha Wildner USB_ST_BDMA_LOAD_ERROR, 7912bd3c8bSSascha Wildner USB_ST_BDMA_LOAD_RESTART, 8012bd3c8bSSascha Wildner 8112bd3c8bSSascha Wildner USB_ST_IVAL_DLY, 8212bd3c8bSSascha Wildner USB_ST_IVAL_DLY_ERROR, 8312bd3c8bSSascha Wildner USB_ST_IVAL_DLY_RESTART, 8412bd3c8bSSascha Wildner 8512bd3c8bSSascha Wildner USB_ST_PIPE_STALL, 8612bd3c8bSSascha Wildner USB_ST_PIPE_STALL_ERROR, 8712bd3c8bSSascha Wildner USB_ST_PIPE_STALL_RESTART, 8812bd3c8bSSascha Wildner 8912bd3c8bSSascha Wildner USB_ST_ENTER, 9012bd3c8bSSascha Wildner USB_ST_ENTER_ERROR, 9112bd3c8bSSascha Wildner USB_ST_ENTER_RESTART, 9212bd3c8bSSascha Wildner 9312bd3c8bSSascha Wildner USB_ST_START, 9412bd3c8bSSascha Wildner USB_ST_START_ERROR, 9512bd3c8bSSascha Wildner USB_ST_START_RESTART, 9612bd3c8bSSascha Wildner 9712bd3c8bSSascha Wildner USB_ST_PIPE_CLOSE, 9812bd3c8bSSascha Wildner USB_ST_PIPE_CLOSE_ERROR, 9912bd3c8bSSascha Wildner USB_ST_PIPE_CLOSE_RESTART, 10012bd3c8bSSascha Wildner 10112bd3c8bSSascha Wildner USB_ST_BDMA_DLY, 10212bd3c8bSSascha Wildner USB_ST_BDMA_DLY_ERROR, 10312bd3c8bSSascha Wildner USB_ST_BDMA_DLY_RESTART, 10412bd3c8bSSascha Wildner 10512bd3c8bSSascha Wildner /* XFER transfer wait states */ 10612bd3c8bSSascha Wildner 10712bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_OPEN = 64, 10812bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_OPEN_ERROR, 10912bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_OPEN_RESTART, 11012bd3c8bSSascha Wildner 11112bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_LOAD, 11212bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_LOAD_ERROR, 11312bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_LOAD_RESTART, 11412bd3c8bSSascha Wildner 11512bd3c8bSSascha Wildner USB_ST_WAIT_IVAL_DLY, 11612bd3c8bSSascha Wildner USB_ST_WAIT_IVAL_DLY_ERROR, 11712bd3c8bSSascha Wildner USB_ST_WAIT_IVAL_DLY_RESTART, 11812bd3c8bSSascha Wildner 11912bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_STALL, 12012bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_STALL_ERROR, 12112bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_STALL_RESTART, 12212bd3c8bSSascha Wildner 12312bd3c8bSSascha Wildner USB_ST_WAIT_ENTER, 12412bd3c8bSSascha Wildner USB_ST_WAIT_ENTER_ERROR, 12512bd3c8bSSascha Wildner USB_ST_WAIT_ENTER_RESTART, 12612bd3c8bSSascha Wildner 12712bd3c8bSSascha Wildner USB_ST_WAIT_START, 12812bd3c8bSSascha Wildner USB_ST_WAIT_START_ERROR, 12912bd3c8bSSascha Wildner USB_ST_WAIT_START_RESTART, 13012bd3c8bSSascha Wildner 13112bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_CLOSE, 13212bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_CLOSE_ERROR, 13312bd3c8bSSascha Wildner USB_ST_WAIT_PIPE_CLOSE_RESTART, 13412bd3c8bSSascha Wildner 13512bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_DLY, 13612bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_DLY_ERROR, 13712bd3c8bSSascha Wildner USB_ST_WAIT_BDMA_DLY_RESTART, 13812bd3c8bSSascha Wildner 13912bd3c8bSSascha Wildner USB_ST_WAIT_TRANSFERRED, 14012bd3c8bSSascha Wildner USB_ST_WAIT_TRANSFERRED_ERROR, 14112bd3c8bSSascha Wildner USB_ST_WAIT_TRANSFERRED_RESTART, 14212bd3c8bSSascha Wildner }; 14312bd3c8bSSascha Wildner 14412bd3c8bSSascha Wildner /* 14512bd3c8bSSascha Wildner * The following structure defines the messages that is used to signal 14612bd3c8bSSascha Wildner * the "done_p" USB process. 14712bd3c8bSSascha Wildner */ 14812bd3c8bSSascha Wildner struct usb_done_msg { 14912bd3c8bSSascha Wildner struct usb_proc_msg hdr; 15012bd3c8bSSascha Wildner struct usb_xfer_root *xroot; 15112bd3c8bSSascha Wildner }; 15212bd3c8bSSascha Wildner 15312bd3c8bSSascha Wildner #define USB_DMATAG_TO_XROOT(dpt) \ 15412bd3c8bSSascha Wildner ((struct usb_xfer_root *)( \ 15512bd3c8bSSascha Wildner ((uint8_t *)(dpt)) - \ 15657bed822SMarkus Pfeiffer ((uint8_t *)&((struct usb_xfer_root *)0)->dma_parent_tag))) 15712bd3c8bSSascha Wildner 15812bd3c8bSSascha Wildner /* 15912bd3c8bSSascha Wildner * The following structure is used to keep information about memory 16012bd3c8bSSascha Wildner * that should be automatically freed at the moment all USB transfers 16112bd3c8bSSascha Wildner * have been freed. 16212bd3c8bSSascha Wildner */ 16312bd3c8bSSascha Wildner struct usb_xfer_root { 16412bd3c8bSSascha Wildner struct usb_dma_parent_tag dma_parent_tag; 16512bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 16612bd3c8bSSascha Wildner struct usb_xfer_queue dma_q; 16712bd3c8bSSascha Wildner #endif 16812bd3c8bSSascha Wildner struct usb_xfer_queue done_q; 16912bd3c8bSSascha Wildner struct usb_done_msg done_m[2]; 17012bd3c8bSSascha Wildner struct cv cv_drain; 17112bd3c8bSSascha Wildner 17212bd3c8bSSascha Wildner struct usb_process *done_p; /* pointer to callback process */ 17312bd3c8bSSascha Wildner void *memory_base; 174722d05c3SSascha Wildner struct lock *xfer_lock; /* cannot be changed during operation */ 17512bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 17612bd3c8bSSascha Wildner struct usb_page_cache *dma_page_cache_start; 17712bd3c8bSSascha Wildner struct usb_page_cache *dma_page_cache_end; 17812bd3c8bSSascha Wildner #endif 17912bd3c8bSSascha Wildner struct usb_page_cache *xfer_page_cache_start; 18012bd3c8bSSascha Wildner struct usb_page_cache *xfer_page_cache_end; 18112bd3c8bSSascha Wildner struct usb_bus *bus; /* pointer to USB bus (cached) */ 18212bd3c8bSSascha Wildner struct usb_device *udev; /* pointer to USB device */ 18312bd3c8bSSascha Wildner 18412bd3c8bSSascha Wildner usb_size_t memory_size; 18512bd3c8bSSascha Wildner usb_size_t setup_refcount; 18612bd3c8bSSascha Wildner #if USB_HAVE_BUSDMA 18712bd3c8bSSascha Wildner usb_frcount_t dma_nframes; /* number of page caches to load */ 18812bd3c8bSSascha Wildner usb_frcount_t dma_currframe; /* currect page cache number */ 18912bd3c8bSSascha Wildner usb_frlength_t dma_frlength_0; /* length of page cache zero */ 19012bd3c8bSSascha Wildner uint8_t dma_error; /* set if virtual memory could not be 19112bd3c8bSSascha Wildner * loaded */ 19212bd3c8bSSascha Wildner #endif 19312bd3c8bSSascha Wildner uint8_t done_sleep; /* set if done thread is sleeping */ 19412bd3c8bSSascha Wildner }; 19512bd3c8bSSascha Wildner 19612bd3c8bSSascha Wildner /* 19712bd3c8bSSascha Wildner * The following structure is used when setting up an array of USB 19812bd3c8bSSascha Wildner * transfers. 19912bd3c8bSSascha Wildner */ 20012bd3c8bSSascha Wildner struct usb_setup_params { 20112bd3c8bSSascha Wildner struct usb_dma_tag *dma_tag_p; 20212bd3c8bSSascha Wildner struct usb_page *dma_page_ptr; 20312bd3c8bSSascha Wildner struct usb_page_cache *dma_page_cache_ptr; /* these will be 20412bd3c8bSSascha Wildner * auto-freed */ 20512bd3c8bSSascha Wildner struct usb_page_cache *xfer_page_cache_ptr; /* these will not be 20612bd3c8bSSascha Wildner * auto-freed */ 20712bd3c8bSSascha Wildner struct usb_device *udev; 20812bd3c8bSSascha Wildner struct usb_xfer *curr_xfer; 20912bd3c8bSSascha Wildner const struct usb_config *curr_setup; 21012bd3c8bSSascha Wildner const struct usb_pipe_methods *methods; 21112bd3c8bSSascha Wildner void *buf; 21212bd3c8bSSascha Wildner usb_frlength_t *xfer_length_ptr; 21312bd3c8bSSascha Wildner 21412bd3c8bSSascha Wildner usb_size_t size[7]; 21512bd3c8bSSascha Wildner usb_frlength_t bufsize; 21612bd3c8bSSascha Wildner usb_frlength_t bufsize_max; 21712bd3c8bSSascha Wildner 21812bd3c8bSSascha Wildner uint32_t hc_max_frame_size; 21912bd3c8bSSascha Wildner uint16_t hc_max_packet_size; 22012bd3c8bSSascha Wildner uint8_t hc_max_packet_count; 22112bd3c8bSSascha Wildner enum usb_dev_speed speed; 22212bd3c8bSSascha Wildner uint8_t dma_tag_max; 22312bd3c8bSSascha Wildner usb_error_t err; 22412bd3c8bSSascha Wildner }; 22512bd3c8bSSascha Wildner 22612bd3c8bSSascha Wildner /* function prototypes */ 22712bd3c8bSSascha Wildner 22812bd3c8bSSascha Wildner uint8_t usbd_transfer_setup_sub_malloc(struct usb_setup_params *parm, 22912bd3c8bSSascha Wildner struct usb_page_cache **ppc, usb_size_t size, usb_size_t align, 23012bd3c8bSSascha Wildner usb_size_t count); 23112bd3c8bSSascha Wildner void usb_dma_delay_done_cb(struct usb_xfer *); 23212bd3c8bSSascha Wildner void usb_command_wrapper(struct usb_xfer_queue *pq, 23312bd3c8bSSascha Wildner struct usb_xfer *xfer); 23412bd3c8bSSascha Wildner void usbd_pipe_enter(struct usb_xfer *xfer); 23512bd3c8bSSascha Wildner void usbd_pipe_start(struct usb_xfer_queue *pq); 23612bd3c8bSSascha Wildner void usbd_transfer_dequeue(struct usb_xfer *xfer); 23712bd3c8bSSascha Wildner void usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error); 23812bd3c8bSSascha Wildner void usbd_transfer_enqueue(struct usb_xfer_queue *pq, 23912bd3c8bSSascha Wildner struct usb_xfer *xfer); 24012bd3c8bSSascha Wildner void usbd_transfer_setup_sub(struct usb_setup_params *parm); 24112bd3c8bSSascha Wildner void usbd_ctrl_transfer_setup(struct usb_device *udev); 24212bd3c8bSSascha Wildner void usbd_clear_stall_locked(struct usb_device *udev, 24312bd3c8bSSascha Wildner struct usb_endpoint *ep); 24412bd3c8bSSascha Wildner void usbd_clear_data_toggle(struct usb_device *udev, 24512bd3c8bSSascha Wildner struct usb_endpoint *ep); 24612bd3c8bSSascha Wildner usb_callback_t usbd_do_request_callback; 24712bd3c8bSSascha Wildner usb_callback_t usb_handle_request_callback; 24812bd3c8bSSascha Wildner usb_callback_t usb_do_clear_stall_callback; 24912bd3c8bSSascha Wildner void usbd_transfer_timeout_ms(struct usb_xfer *xfer, 25012bd3c8bSSascha Wildner void (*cb) (void *arg), usb_timeout_t ms); 25112bd3c8bSSascha Wildner usb_timeout_t usbd_get_dma_delay(struct usb_device *udev); 25212bd3c8bSSascha Wildner void usbd_transfer_power_ref(struct usb_xfer *xfer, int val); 25312bd3c8bSSascha Wildner 25412bd3c8bSSascha Wildner #endif /* _USB_TRANSFER_H_ */ 255