diff options
author | Jan Andersson <jan@gaisler.com> | 2011-05-06 06:00:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-06 21:23:59 -0400 |
commit | e7652e1ebc0f5e07929067ece14ca869dad20dd6 (patch) | |
tree | cbdca7e57d94be0be8fcee5f6f412eec937188ef /drivers/usb/host/uhci-hcd.c | |
parent | dfeca7a8750296a7d065d45257b3cd86aadc3fb9 (diff) |
USB: UHCI: Allow dynamic assignment of bus specific functions
This patch is part of a series that extend the UHCI HCD to support
non-PCI controllers.
This patch changes calls to uhci_reset_hc, uhci_check_and_reset_hc,
configure_hc, resume_detect_interrupts_are_broken and
global_suspend_mode_is_broken so that they are made through pointers
in the uhci hcd struct. This will allow these functions to be replaced
with bus/arch specific functions.
Signed-off-by: Jan Andersson <jan@gaisler.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-hcd.c')
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 214851a6244f..683e87e49a03 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -143,13 +143,22 @@ static void finish_reset(struct uhci_hcd *uhci) | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * Make sure the controller is completely inactive, unable to | ||
147 | * generate interrupts or do DMA. | ||
148 | */ | ||
149 | static void uhci_pci_reset_hc(struct uhci_hcd *uhci) | ||
150 | { | ||
151 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); | ||
152 | } | ||
153 | |||
154 | /* | ||
146 | * Last rites for a defunct/nonfunctional controller | 155 | * Last rites for a defunct/nonfunctional controller |
147 | * or one we don't want to use any more. | 156 | * or one we don't want to use any more. |
148 | */ | 157 | */ |
149 | static void uhci_hc_died(struct uhci_hcd *uhci) | 158 | static void uhci_hc_died(struct uhci_hcd *uhci) |
150 | { | 159 | { |
151 | uhci_get_current_frame_number(uhci); | 160 | uhci_get_current_frame_number(uhci); |
152 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); | 161 | uhci->reset_hc(uhci); |
153 | finish_reset(uhci); | 162 | finish_reset(uhci); |
154 | uhci->dead = 1; | 163 | uhci->dead = 1; |
155 | 164 | ||
@@ -158,23 +167,45 @@ static void uhci_hc_died(struct uhci_hcd *uhci) | |||
158 | } | 167 | } |
159 | 168 | ||
160 | /* | 169 | /* |
170 | * Initialize a controller that was newly discovered or has just been | ||
171 | * resumed. In either case we can't be sure of its previous state. | ||
172 | * | ||
173 | * Returns: 1 if the controller was reset, 0 otherwise. | ||
174 | */ | ||
175 | static int uhci_pci_check_and_reset_hc(struct uhci_hcd *uhci) | ||
176 | { | ||
177 | return uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), | ||
178 | uhci->io_addr); | ||
179 | } | ||
180 | |||
181 | /* | ||
161 | * Initialize a controller that was newly discovered or has lost power | 182 | * Initialize a controller that was newly discovered or has lost power |
162 | * or otherwise been reset while it was suspended. In none of these cases | 183 | * or otherwise been reset while it was suspended. In none of these cases |
163 | * can we be sure of its previous state. | 184 | * can we be sure of its previous state. |
164 | */ | 185 | */ |
165 | static void check_and_reset_hc(struct uhci_hcd *uhci) | 186 | static void check_and_reset_hc(struct uhci_hcd *uhci) |
166 | { | 187 | { |
167 | if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr)) | 188 | if (uhci->check_and_reset_hc(uhci)) |
168 | finish_reset(uhci); | 189 | finish_reset(uhci); |
169 | } | 190 | } |
170 | 191 | ||
192 | static void uhci_pci_configure_hc(struct uhci_hcd *uhci) | ||
193 | { | ||
194 | struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); | ||
195 | |||
196 | /* Enable PIRQ */ | ||
197 | pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT); | ||
198 | |||
199 | /* Disable platform-specific non-PME# wakeup */ | ||
200 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
201 | pci_write_config_byte(pdev, USBRES_INTEL, 0); | ||
202 | } | ||
203 | |||
171 | /* | 204 | /* |
172 | * Store the basic register settings needed by the controller. | 205 | * Store the basic register settings needed by the controller. |
173 | */ | 206 | */ |
174 | static void configure_hc(struct uhci_hcd *uhci) | 207 | static void configure_hc(struct uhci_hcd *uhci) |
175 | { | 208 | { |
176 | struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); | ||
177 | |||
178 | /* Set the frame length to the default: 1 ms exactly */ | 209 | /* Set the frame length to the default: 1 ms exactly */ |
179 | outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); | 210 | outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); |
180 | 211 | ||
@@ -185,24 +216,15 @@ static void configure_hc(struct uhci_hcd *uhci) | |||
185 | outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER, | 216 | outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER, |
186 | uhci->io_addr + USBFRNUM); | 217 | uhci->io_addr + USBFRNUM); |
187 | 218 | ||
188 | /* Enable PIRQ */ | 219 | /* perform any arch/bus specific configuration */ |
189 | pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT); | 220 | if (uhci->configure_hc) |
190 | 221 | uhci->configure_hc(uhci); | |
191 | /* Disable platform-specific non-PME# wakeup */ | ||
192 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
193 | pci_write_config_byte(pdev, USBRES_INTEL, 0); | ||
194 | } | 222 | } |
195 | 223 | ||
196 | 224 | static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) | |
197 | static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) | ||
198 | { | 225 | { |
199 | int port; | 226 | int port; |
200 | 227 | ||
201 | /* If we have to ignore overcurrent events then almost by definition | ||
202 | * we can't depend on resume-detect interrupts. */ | ||
203 | if (ignore_oc) | ||
204 | return 1; | ||
205 | |||
206 | switch (to_pci_dev(uhci_dev(uhci))->vendor) { | 228 | switch (to_pci_dev(uhci_dev(uhci))->vendor) { |
207 | default: | 229 | default: |
208 | break; | 230 | break; |
@@ -231,7 +253,18 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) | |||
231 | return 0; | 253 | return 0; |
232 | } | 254 | } |
233 | 255 | ||
234 | static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) | 256 | static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) |
257 | { | ||
258 | /* If we have to ignore overcurrent events then almost by definition | ||
259 | * we can't depend on resume-detect interrupts. */ | ||
260 | if (ignore_oc) | ||
261 | return 1; | ||
262 | |||
263 | return uhci->resume_detect_interrupts_are_broken ? | ||
264 | uhci->resume_detect_interrupts_are_broken(uhci) : 0; | ||
265 | } | ||
266 | |||
267 | static int uhci_pci_global_suspend_mode_is_broken(struct uhci_hcd *uhci) | ||
235 | { | 268 | { |
236 | int port; | 269 | int port; |
237 | const char *sys_info; | 270 | const char *sys_info; |
@@ -253,6 +286,12 @@ static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) | |||
253 | return 0; | 286 | return 0; |
254 | } | 287 | } |
255 | 288 | ||
289 | static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) | ||
290 | { | ||
291 | return uhci->global_suspend_mode_is_broken ? | ||
292 | uhci->global_suspend_mode_is_broken(uhci) : 0; | ||
293 | } | ||
294 | |||
256 | static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) | 295 | static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) |
257 | __releases(uhci->lock) | 296 | __releases(uhci->lock) |
258 | __acquires(uhci->lock) | 297 | __acquires(uhci->lock) |
@@ -557,6 +596,16 @@ static int uhci_init(struct usb_hcd *hcd) | |||
557 | if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) | 596 | if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) |
558 | uhci->wait_for_hp = 1; | 597 | uhci->wait_for_hp = 1; |
559 | 598 | ||
599 | /* Set up pointers to PCI-specific functions */ | ||
600 | uhci->reset_hc = uhci_pci_reset_hc; | ||
601 | uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc; | ||
602 | uhci->configure_hc = uhci_pci_configure_hc; | ||
603 | uhci->resume_detect_interrupts_are_broken = | ||
604 | uhci_pci_resume_detect_interrupts_are_broken; | ||
605 | uhci->global_suspend_mode_is_broken = | ||
606 | uhci_pci_global_suspend_mode_is_broken; | ||
607 | |||
608 | |||
560 | /* Kick BIOS off this hardware and reset if the controller | 609 | /* Kick BIOS off this hardware and reset if the controller |
561 | * isn't already safely quiescent. | 610 | * isn't already safely quiescent. |
562 | */ | 611 | */ |
@@ -847,7 +896,7 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
847 | 896 | ||
848 | /* Make sure resume from hibernation re-enumerates everything */ | 897 | /* Make sure resume from hibernation re-enumerates everything */ |
849 | if (hibernated) { | 898 | if (hibernated) { |
850 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); | 899 | uhci->reset_hc(uhci); |
851 | finish_reset(uhci); | 900 | finish_reset(uhci); |
852 | } | 901 | } |
853 | 902 | ||