--- zzzz-none-000/linux-3.10.107/drivers/usb/wusbcore/wa-hc.h 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/usb/wusbcore/wa-hc.h 2021-02-04 17:41:59.000000000 +0000 @@ -36,7 +36,7 @@ * * hcd glue with the USB API Host Controller Interface API. * - * nep Notification EndPoint managent: collect notifications + * nep Notification EndPoint management: collect notifications * and queue them with the workqueue daemon. * * Handle notifications as coming from the NEP. Sends them @@ -64,7 +64,7 @@ * * Note much of the activity is difficult to follow. For example a * device connect goes to devconnect, which will cause the "fake" root - * hub port to show a connect and stop there. Then khubd will notice + * hub port to show a connect and stop there. Then hub_wq will notice * and call into the rh.c:hwahc_rc_port_reset() code to authenticate * the device (and this might require user intervention) and enable * the port. @@ -91,6 +91,7 @@ struct wusbhc; struct wahc; extern void wa_urb_enqueue_run(struct work_struct *ws); +extern void wa_process_errored_transfers_run(struct work_struct *ws); /** * RPipe instance @@ -116,11 +117,38 @@ struct wahc *wa; spinlock_t seg_lock; struct list_head seg_list; + struct list_head list_node; atomic_t segs_available; u8 buffer[1]; /* For reads/writes on USB */ }; +enum wa_dti_state { + WA_DTI_TRANSFER_RESULT_PENDING, + WA_DTI_ISOC_PACKET_STATUS_PENDING, + WA_DTI_BUF_IN_DATA_PENDING +}; + +enum wa_quirks { + /* + * The Alereon HWA expects the data frames in isochronous transfer + * requests to be concatenated and not sent as separate packets. + */ + WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01, + /* + * The Alereon HWA can be instructed to not send transfer notifications + * as an optimization. + */ + WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS = 0x02, +}; + +enum wa_vendor_specific_requests { + WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C, + WA_REQ_ALEREON_FEATURE_SET = 0x01, + WA_REQ_ALEREON_FEATURE_CLEAR = 0x00, +}; + +#define WA_MAX_BUF_IN_URBS 4 /** * Instance of a HWA Host Controller * @@ -129,7 +157,7 @@ * * @wa_descr Can be accessed without locking because it is in * the same area where the device descriptors were - * read, so it is guaranteed to exist umodified while + * read, so it is guaranteed to exist unmodified while * the device exists. * * Endianess has been converted to CPU's. @@ -152,8 +180,8 @@ * submitted from an atomic context). * * FIXME: this needs to be layered up: a wusbhc layer (for sharing - * comonalities with WHCI), a wa layer (for sharing - * comonalities with DWA-RC). + * commonalities with WHCI), a wa layer (for sharing + * commonalities with DWA-RC). */ struct wahc { struct usb_device *usb_dev; @@ -177,27 +205,51 @@ u16 rpipes; unsigned long *rpipe_bm; /* rpipe usage bitmap */ - spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ + struct list_head rpipe_delayed_list; /* delayed RPIPES. */ + spinlock_t rpipe_lock; /* protect rpipe_bm and delayed list */ struct mutex rpipe_mutex; /* assigning resources to endpoints */ + /* + * dti_state is used to track the state of the dti_urb. When dti_state + * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and + * dti_isoc_xfer_seg identify which xfer the incoming isoc packet + * status refers to. + */ + enum wa_dti_state dti_state; + u32 dti_isoc_xfer_in_progress; + u8 dti_isoc_xfer_seg; struct urb *dti_urb; /* URB for reading xfer results */ - struct urb *buf_in_urb; /* URB for reading data in */ + /* URBs for reading data in */ + struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS]; + int active_buf_in_urbs; /* number of buf_in_urbs active. */ struct edc dti_edc; /* DTI error density counter */ - struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ - size_t xfer_result_size; + void *dti_buf; + size_t dti_buf_size; + + unsigned long dto_in_use; /* protect dto endoint serialization */ s32 status; /* For reading status */ struct list_head xfer_list; struct list_head xfer_delayed_list; + struct list_head xfer_errored_list; + /* + * lock for the above xfer lists. Can be taken while a xfer->lock is + * held but not in the reverse order. + */ spinlock_t xfer_list_lock; - struct work_struct xfer_work; + struct work_struct xfer_enqueue_work; + struct work_struct xfer_error_work; atomic_t xfer_id_count; + + kernel_ulong_t quirks; }; -extern int wa_create(struct wahc *wa, struct usb_interface *iface); +extern int wa_create(struct wahc *wa, struct usb_interface *iface, + kernel_ulong_t); extern void __wa_destroy(struct wahc *wa); +extern int wa_dti_start(struct wahc *wa); void wa_reset_all(struct wahc *wa); @@ -232,21 +284,32 @@ /* RPipes */ static inline void wa_rpipe_init(struct wahc *wa) { - spin_lock_init(&wa->rpipe_bm_lock); + INIT_LIST_HEAD(&wa->rpipe_delayed_list); + spin_lock_init(&wa->rpipe_lock); mutex_init(&wa->rpipe_mutex); } static inline void wa_init(struct wahc *wa) { + int index; + edc_init(&wa->nep_edc); atomic_set(&wa->notifs_queued, 0); + wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING; wa_rpipe_init(wa); edc_init(&wa->dti_edc); INIT_LIST_HEAD(&wa->xfer_list); INIT_LIST_HEAD(&wa->xfer_delayed_list); + INIT_LIST_HEAD(&wa->xfer_errored_list); spin_lock_init(&wa->xfer_list_lock); - INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); + INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run); + INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run); + wa->dto_in_use = 0; atomic_set(&wa->xfer_id_count, 1); + /* init the buf in URBs */ + for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) + usb_init_urb(&(wa->buf_in_urbs[index])); + wa->active_buf_in_urbs = 0; } /** @@ -269,6 +332,8 @@ } extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); +extern void rpipe_clear_feature_stalled(struct wahc *, + struct usb_host_endpoint *); extern int wa_rpipes_create(struct wahc *); extern void wa_rpipes_destroy(struct wahc *); static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) @@ -289,7 +354,7 @@ /* Transferring data */ extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, struct urb *, gfp_t); -extern int wa_urb_dequeue(struct wahc *, struct urb *); +extern int wa_urb_dequeue(struct wahc *, struct urb *, int); extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); @@ -302,7 +367,7 @@ * it...no RC specific function is called...unless I miss * something. * - * FIXME: has to go away in favour of an 'struct' hcd based sollution + * FIXME: has to go away in favour of a 'struct' hcd based solution */ static inline struct wahc *wa_get(struct wahc *wa) { @@ -323,7 +388,7 @@ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, feature, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); + NULL, 0, USB_CTRL_SET_TIMEOUT); } @@ -357,8 +422,7 @@ USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - &wa->status, sizeof(wa->status), - 1000 /* FIXME: arbitrary */); + &wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT); if (result >= 0) result = wa->status; return result;