2005-04-17 02:20:36 +04:00
/*
* cardbus . c - - 16 - bit PCMCIA core support
*
* 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 .
*
* The initial developer of the original code is David A . Hinds
* < dahinds @ users . sourceforge . net > . Portions created by David A . Hinds
* are Copyright ( C ) 1999 David A . Hinds . All Rights Reserved .
*
* ( C ) 1999 David A . Hinds
*/
/*
* Cardbus handling has been re - written to be more of a PCI bridge thing ,
* and the PCI code basically does all the resource handling .
*
* Linus , Jan 2000
*/
# include <linux/kernel.h>
2010-01-02 19:27:33 +03:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <linux/pci.h>
# include <pcmcia/ss.h>
2009-09-22 12:34:48 +04:00
static void cardbus_config_irq_and_cls ( struct pci_bus * bus , int irq )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
u8 irq_pin ;
2009-09-22 12:34:48 +04:00
/*
* Since there is only one interrupt available to
* CardBus devices , all devices downstream of this
* device must be using this IRQ .
*/
2005-04-17 02:20:36 +04:00
pci_read_config_byte ( dev , PCI_INTERRUPT_PIN , & irq_pin ) ;
if ( irq_pin ) {
dev - > irq = irq ;
pci_write_config_byte ( dev , PCI_INTERRUPT_LINE , dev - > irq ) ;
}
2009-09-22 12:34:48 +04:00
/*
* Some controllers transfer very slowly with 0 CLS .
* Configure it . This may fail as CLS configuration
* is mandatory only for MWI .
*/
pci_set_cacheline_size ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( dev - > subordinate )
2009-09-22 12:34:48 +04:00
cardbus_config_irq_and_cls ( dev - > subordinate , irq ) ;
2005-04-17 02:20:36 +04:00
}
}
2010-01-02 19:27:33 +03:00
/**
* cb_alloc ( ) - add CardBus device
* @ s : the pcmcia_socket where the CardBus device is located
*
* cb_alloc ( ) allocates the kernel data structures for a Cardbus device
* and handles the lowest level PCI device setup issues .
*/
2009-12-08 00:11:45 +03:00
int __ref cb_alloc ( struct pcmcia_socket * s )
2005-04-17 02:20:36 +04:00
{
struct pci_bus * bus = s - > cb_dev - > subordinate ;
struct pci_dev * dev ;
unsigned int max , pass ;
2014-01-10 18:25:34 +04:00
pci_lock_rescan_remove ( ) ;
2005-04-17 02:20:36 +04:00
s - > functions = pci_scan_slot ( bus , PCI_DEVFN ( 0 , 0 ) ) ;
2010-03-02 10:57:33 +03:00
pci_fixup_cardbus ( bus ) ;
2005-04-17 02:20:36 +04:00
2012-05-18 05:51:11 +04:00
max = bus - > busn_res . start ;
2005-04-17 02:20:36 +04:00
for ( pass = 0 ; pass < 2 ; pass + + )
list_for_each_entry ( dev , & bus - > devices , bus_list )
2014-05-04 08:23:47 +04:00
if ( pci_is_bridge ( dev ) )
2005-04-17 02:20:36 +04:00
max = pci_scan_bridge ( bus , dev , max , pass ) ;
/*
* Size all resources below the CardBus controller .
*/
pci_bus_size_bridges ( bus ) ;
pci_bus_assign_resources ( bus ) ;
2009-09-22 12:34:48 +04:00
cardbus_config_irq_and_cls ( bus , s - > pci_irq ) ;
2005-08-22 09:29:26 +04:00
/* socket specific tune function */
if ( s - > tune_bridge )
s - > tune_bridge ( s , bus ) ;
2005-04-17 02:20:36 +04:00
pci_bus_add_devices ( bus ) ;
2014-01-10 18:25:34 +04:00
pci_unlock_rescan_remove ( ) ;
2008-08-03 12:07:45 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-01-02 19:27:33 +03:00
/**
* cb_free ( ) - remove CardBus device
* @ s : the pcmcia_socket where the CardBus device was located
*
* cb_free ( ) handles the lowest level PCI device cleanup .
*/
2009-12-08 00:11:45 +03:00
void cb_free ( struct pcmcia_socket * s )
2005-04-17 02:20:36 +04:00
{
2012-08-17 20:49:04 +04:00
struct pci_dev * bridge , * dev , * tmp ;
struct pci_bus * bus ;
2005-04-17 02:20:36 +04:00
2012-08-17 20:49:04 +04:00
bridge = s - > cb_dev ;
if ( ! bridge )
return ;
bus = bridge - > subordinate ;
if ( ! bus )
return ;
2014-01-10 18:25:34 +04:00
pci_lock_rescan_remove ( ) ;
2012-08-17 20:49:04 +04:00
list_for_each_entry_safe ( dev , tmp , & bus - > devices , bus_list )
pci_stop_and_remove_bus_device ( dev ) ;
2014-01-10 18:25:34 +04:00
pci_unlock_rescan_remove ( ) ;
2005-04-17 02:20:36 +04:00
}