2009-04-28 06:52:28 +04:00
/*
* xHCI host controller driver PCI Bus Glue .
*
* Copyright ( C ) 2008 Intel Corp .
*
* Author : Sarah Sharp
* Some code borrowed from the Linux EHCI driver .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/pci.h>
# include "xhci.h"
static const char hcd_name [ ] = " xhci_hcd " ;
/* called after powerup, by probe or system-pm "wakeup" */
static int xhci_pci_reinit ( struct xhci_hcd * xhci , struct pci_dev * pdev )
{
/*
* TODO : Implement finding debug ports later .
* TODO : see if there are any quirks that need to be added to handle
* new extended capabilities .
*/
/* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
if ( ! pci_set_mwi ( pdev ) )
xhci_dbg ( xhci , " MWI active \n " ) ;
xhci_dbg ( xhci , " Finished xhci_pci_reinit \n " ) ;
return 0 ;
}
/* called during probe() after chip reset completes */
static int xhci_pci_setup ( struct usb_hcd * hcd )
{
struct xhci_hcd * xhci = hcd_to_xhci ( hcd ) ;
struct pci_dev * pdev = to_pci_dev ( hcd - > self . controller ) ;
int retval ;
xhci - > cap_regs = hcd - > regs ;
xhci - > op_regs = hcd - > regs +
HC_LENGTH ( xhci_readl ( xhci , & xhci - > cap_regs - > hc_capbase ) ) ;
xhci - > run_regs = hcd - > regs +
( xhci_readl ( xhci , & xhci - > cap_regs - > run_regs_off ) & RTSOFF_MASK ) ;
/* Cache read-only capability registers */
xhci - > hcs_params1 = xhci_readl ( xhci , & xhci - > cap_regs - > hcs_params1 ) ;
xhci - > hcs_params2 = xhci_readl ( xhci , & xhci - > cap_regs - > hcs_params2 ) ;
xhci - > hcs_params3 = xhci_readl ( xhci , & xhci - > cap_regs - > hcs_params3 ) ;
xhci - > hcc_params = xhci_readl ( xhci , & xhci - > cap_regs - > hcc_params ) ;
xhci_print_registers ( xhci ) ;
/* Make sure the HC is halted. */
retval = xhci_halt ( xhci ) ;
if ( retval )
return retval ;
xhci_dbg ( xhci , " Resetting HCD \n " ) ;
/* Reset the internal HC memory state and registers. */
retval = xhci_reset ( xhci ) ;
if ( retval )
return retval ;
xhci_dbg ( xhci , " Reset complete \n " ) ;
xhci_dbg ( xhci , " Calling HCD init \n " ) ;
/* Initialize HCD and host controller data structures. */
retval = xhci_init ( hcd ) ;
if ( retval )
return retval ;
xhci_dbg ( xhci , " Called HCD init \n " ) ;
pci_read_config_byte ( pdev , XHCI_SBRN_OFFSET , & xhci - > sbrn ) ;
xhci_dbg ( xhci , " Got SBRN %u \n " , ( unsigned int ) xhci - > sbrn ) ;
/* Find any debug ports */
return xhci_pci_reinit ( xhci , pdev ) ;
}
static const struct hc_driver xhci_pci_hc_driver = {
. description = hcd_name ,
. product_desc = " xHCI Host Controller " ,
. hcd_priv_size = sizeof ( struct xhci_hcd ) ,
/*
* generic hardware linkage
*/
2009-04-28 06:53:56 +04:00
. irq = xhci_irq ,
2009-04-28 06:52:28 +04:00
. flags = HCD_MEMORY | HCD_USB3 ,
/*
* basic lifecycle operations
*/
. reset = xhci_pci_setup ,
. start = xhci_run ,
/* suspend and resume implemented later */
. stop = xhci_stop ,
. shutdown = xhci_shutdown ,
2009-04-28 06:57:38 +04:00
/*
* managing i / o requests and associated device resources
*/
. alloc_dev = xhci_alloc_dev ,
. free_dev = xhci_free_dev ,
. address_device = xhci_address_device ,
2009-04-28 06:52:28 +04:00
/*
* scheduling support
*/
. get_frame_number = xhci_get_frame ,
2009-04-28 06:57:12 +04:00
/* Root hub support */
. hub_control = xhci_hub_control ,
. hub_status_data = xhci_hub_status_data ,
2009-04-28 06:52:28 +04:00
} ;
/*-------------------------------------------------------------------------*/
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [ ] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS ( PCI_CLASS_SERIAL_USB_XHCI , ~ 0 ) ,
. driver_data = ( unsigned long ) & xhci_pci_hc_driver ,
} ,
{ /* end: all zeroes */ }
} ;
MODULE_DEVICE_TABLE ( pci , pci_ids ) ;
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
. name = ( char * ) hcd_name ,
. id_table = pci_ids ,
. probe = usb_hcd_pci_probe ,
. remove = usb_hcd_pci_remove ,
/* suspend and resume implemented later */
. shutdown = usb_hcd_pci_shutdown ,
} ;
int xhci_register_pci ( )
{
return pci_register_driver ( & xhci_pci_driver ) ;
}
void xhci_unregister_pci ( )
{
pci_unregister_driver ( & xhci_pci_driver ) ;
}