diff options
Diffstat (limited to 'drivers/usb/wusbcore/wa-hc.h')
| -rw-r--r-- | drivers/usb/wusbcore/wa-hc.h | 98 | 
1 files changed, 81 insertions, 17 deletions
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h index d6bea3e0b54..f2a8d29e17b 100644 --- a/drivers/usb/wusbcore/wa-hc.h +++ b/drivers/usb/wusbcore/wa-hc.h @@ -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 @@ -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 wa_rpipe {  	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 @@ struct wa_rpipe {   *   * @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 @@ struct wa_rpipe {   *                       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 @@ struct wahc {  	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 @@ static inline void wa_nep_disarm(struct wahc *wa)  /* 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 @@ static inline void rpipe_put(struct wa_rpipe *rpipe)  }  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 @@ static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)  /* 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 @@ extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);   *        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 @@ static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)  			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 @@ s32 __wa_get_status(struct wahc *wa)  		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;  | 
