struct list_head remove_list; /* P: uhci->remove_list_lock */
} __attribute__((aligned(16)));
+/*
+ * We need a special accessor for the element pointer because it is
+ * subject to asynchronous updates by the controller
+ */
+static __le32 inline qh_element(struct uhci_qh *qh) {
+ __le32 element = qh->element;
+
+ barrier();
+ return element;
+}
+
/*
* for TD <status>:
*/
-#define td_status(td) le32_to_cpu((td)->status)
#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
#define TD_CTRL_C_ERR_SHIFT 27
struct list_head fl_list; /* P: uhci->frame_list_lock */
} __attribute__((aligned(16)));
+/*
+ * We need a special accessor for the control/status word because it is
+ * subject to asynchronous updates by the controller
+ */
+static u32 inline td_status(struct uhci_td *td) {
+ __le32 status = td->status;
+
+ barrier();
+ return le32_to_cpu(status);
+}
+
+
/*
* The UHCI driver places Interrupt, Control and Bulk into QH's both
* to group together TD's for one transfer, and also to faciliate queuing
UHCI_RESUMING_2
};
-#define hcd_to_uhci(hcd_ptr) container_of(hcd_ptr, struct uhci_hcd, hcd)
-#define uhci_dev(u) ((u)->hcd.self.controller)
-
/*
* This describes the full uhci information.
*
* a subset of what the full implementation needs.
*/
struct uhci_hcd {
- struct usb_hcd hcd;
-#ifdef CONFIG_PROC_FS
- /* procfs */
- struct proc_dir_entry *proc_entry;
-#endif
+ /* debugfs */
+ struct dentry *dentry;
/* Grabbed from PCI */
unsigned long io_addr;
struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
- spinlock_t schedule_lock;
- struct uhci_frame_list *fl; /* P: uhci->schedule_lock */
+ spinlock_t lock;
+ struct uhci_frame_list *fl; /* P: uhci->lock */
int fsbr; /* Full-speed bandwidth reclamation */
unsigned long fsbrtimeout; /* FSBR delay */
enum uhci_state state; /* FIXME: needs a spinlock */
unsigned long state_end; /* Time of next transition */
- int resume_detect; /* Need a Global Resume */
- unsigned int saved_framenumber; /* Save during PM suspend */
+ unsigned int frame_number; /* As of last check */
+ unsigned int is_stopped;
+#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */
+
+ unsigned int scan_in_progress:1; /* Schedule scan is running */
+ unsigned int need_rescan:1; /* Redo the schedule scan */
+ unsigned int resume_detect:1; /* Need a Global Resume */
+
+ /* Support for port suspend/resume/reset */
+ unsigned long port_c_suspend; /* Bit-arrays of ports */
+ unsigned long suspended_ports;
+ unsigned long resuming_ports;
+ unsigned long ports_timeout; /* Time to stop signalling */
/* Main list of URB's currently controlled by this HC */
- struct list_head urb_list; /* P: uhci->schedule_lock */
+ struct list_head urb_list; /* P: uhci->lock */
/* List of QH's that are done, but waiting to be unlinked (race) */
- struct list_head qh_remove_list; /* P: uhci->schedule_lock */
+ struct list_head qh_remove_list; /* P: uhci->lock */
unsigned int qh_remove_age; /* Age in frames */
/* List of TD's that are done, but waiting to be freed (race) */
- struct list_head td_remove_list; /* P: uhci->schedule_lock */
+ struct list_head td_remove_list; /* P: uhci->lock */
unsigned int td_remove_age; /* Age in frames */
/* List of asynchronously unlinked URB's */
- struct list_head urb_remove_list; /* P: uhci->schedule_lock */
+ struct list_head urb_remove_list; /* P: uhci->lock */
unsigned int urb_remove_age; /* Age in frames */
/* List of URB's awaiting completion callback */
- struct list_head complete_list; /* P: uhci->schedule_lock */
+ struct list_head complete_list; /* P: uhci->lock */
int rh_numports;
wait_queue_head_t waitqh; /* endpoint_disable waiters */
};
+/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
+static inline struct uhci_hcd *hcd_to_uhci(struct usb_hcd *hcd)
+{
+ return (struct uhci_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
+{
+ return container_of((void *) uhci, struct usb_hcd, hcd_priv);
+}
+
+#define uhci_dev(u) (uhci_to_hcd(u)->self.controller)
+
struct urb_priv {
struct list_head urb_list;
struct uhci_qh *qh; /* QH for this URB */
struct list_head td_list; /* P: urb->lock */
- int fsbr : 1; /* URB turned on FSBR */
- int fsbr_timeout : 1; /* URB timed out on FSBR */
- int queued : 1; /* QH was queued (not linked in) */
- int short_control_packet : 1; /* If we get a short packet during */
- /* a control transfer, retrigger */
- /* the status phase */
+ unsigned fsbr : 1; /* URB turned on FSBR */
+ unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
+ unsigned queued : 1; /* QH was queued (not linked in) */
+ unsigned short_control_packet : 1; /* If we get a short packet during */
+ /* a control transfer, retrigger */
+ /* the status phase */
unsigned long inserttime; /* In jiffies */
unsigned long fsbrtime; /* In jiffies */
* Locking in uhci.c
*
* Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->schedule_lock. urb->status is protected
- * by urb->lock; that's the one exception.
+ * of URBs is protected by uhci->lock. urb->status is protected by
+ * urb->lock; that's the one exception.
*
- * To prevent deadlocks, never lock uhci->schedule_lock while holding
- * urb->lock. The safe order of locking is:
+ * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
+ * The safe order of locking is:
*
- * #1 uhci->schedule_lock
+ * #1 uhci->lock
* #2 urb->lock
*/