2005-05-26 05:55:55 -07:00
/*
* PCMCIA driver for SL811HS ( as found in REX - CFU1U )
* Filename : sl811_cs . c
* Author : Yukio Yamamoto
*
* Port to sl811 - hcd and 2.6 . x by
* Botond Botyanszki < boti @ rocketmail . com >
* Simon Pickering
*
* Last update : 2005 - 05 - 12
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/ioport.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-05-26 05:55:55 -07:00
# include <pcmcia/cs_types.h>
# include <pcmcia/cs.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/cisreg.h>
# include <pcmcia/ds.h>
2006-06-13 09:59:32 -07:00
# include <linux/usb/sl811.h>
2005-05-26 05:55:55 -07:00
MODULE_AUTHOR ( " Botond Botyanszki " ) ;
MODULE_DESCRIPTION ( " REX-CFU1U PCMCIA driver for 2.6 " ) ;
MODULE_LICENSE ( " GPL " ) ;
/*====================================================================*/
/* MACROS */
/*====================================================================*/
2005-11-07 20:45:20 -08:00
# if defined(DEBUG) || defined(PCMCIA_DEBUG)
2005-05-26 05:55:55 -07:00
static int pc_debug = 0 ;
module_param ( pc_debug , int , 0644 ) ;
# define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args)
# else
# define DBG(n, args...) do{}while(0)
# endif /* no debugging */
# define INFO(args...) printk(KERN_INFO "sl811_cs: " args)
# define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
# define CS_CHECK(fn, ret) \
do { \
last_fn = ( fn ) ; \
if ( ( last_ret = ( ret ) ) ! = 0 ) \
goto cs_failed ; \
} while ( 0 )
/*====================================================================*/
/* VARIABLES */
/*====================================================================*/
static const char driver_name [ DEV_NAME_LEN ] = " sl811_cs " ;
typedef struct local_info_t {
2006-03-05 10:45:09 +01:00
struct pcmcia_device * p_dev ;
2005-05-26 05:55:55 -07:00
dev_node_t node ;
} local_info_t ;
2006-03-31 17:21:06 +02:00
static void sl811_cs_release ( struct pcmcia_device * link ) ;
2005-11-14 21:23:14 +01:00
2005-05-26 05:55:55 -07:00
/*====================================================================*/
static void release_platform_dev ( struct device * dev )
{
DBG ( 0 , " sl811_cs platform_dev release \n " ) ;
dev - > parent = NULL ;
}
static struct sl811_platform_data platform_data = {
. potpg = 100 ,
. power = 50 , /* == 100mA */
// .reset = ... FIXME: invoke CF reset on the card
} ;
static struct resource resources [ ] = {
[ 0 ] = {
. flags = IORESOURCE_IRQ ,
} ,
[ 1 ] = {
// .name = "address",
. flags = IORESOURCE_IO ,
} ,
[ 2 ] = {
// .name = "data",
. flags = IORESOURCE_IO ,
} ,
} ;
2006-02-06 12:15:15 -08:00
extern struct platform_driver sl811h_driver ;
2005-05-26 05:55:55 -07:00
static struct platform_device platform_dev = {
. id = - 1 ,
. dev = {
. platform_data = & platform_data ,
. release = release_platform_dev ,
} ,
. resource = resources ,
. num_resources = ARRAY_SIZE ( resources ) ,
} ;
static int sl811_hc_init ( struct device * parent , ioaddr_t base_addr , int irq )
{
if ( platform_dev . dev . parent )
return - EBUSY ;
platform_dev . dev . parent = parent ;
/* finish seting up the platform device */
resources [ 0 ] . start = irq ;
resources [ 1 ] . start = base_addr ;
resources [ 1 ] . end = base_addr ;
resources [ 2 ] . start = base_addr + 1 ;
resources [ 2 ] . end = base_addr + 1 ;
/* The driver core will probe for us. We know sl811-hcd has been
2005-11-07 20:45:20 -08:00
* initialized already because of the link order dependency created
* by referencing " sl811h_driver " .
2005-05-26 05:55:55 -07:00
*/
2006-02-06 12:15:15 -08:00
platform_dev . name = sl811h_driver . driver . name ;
2005-05-26 05:55:55 -07:00
return platform_device_register ( & platform_dev ) ;
}
/*====================================================================*/
2006-03-31 17:21:06 +02:00
static void sl811_cs_detach ( struct pcmcia_device * link )
2005-05-26 05:55:55 -07:00
{
DBG ( 0 , " sl811_cs_detach(0x%p) \n " , link ) ;
2006-03-02 00:09:29 +01:00
sl811_cs_release ( link ) ;
2005-05-26 05:55:55 -07:00
/* This points to the parent local_info_t struct */
kfree ( link - > priv ) ;
}
2006-03-31 17:21:06 +02:00
static void sl811_cs_release ( struct pcmcia_device * link )
2005-05-26 05:55:55 -07:00
{
DBG ( 0 , " sl811_cs_release(0x%p) \n " , link ) ;
2006-03-31 17:21:06 +02:00
pcmcia_disable_device ( link ) ;
2005-05-26 05:55:55 -07:00
platform_device_unregister ( & platform_dev ) ;
}
2006-03-31 17:26:06 +02:00
static int sl811_cs_config ( struct pcmcia_device * link )
2005-05-26 05:55:55 -07:00
{
2006-03-31 17:21:06 +02:00
struct device * parent = & handle_to_dev ( link ) ;
2005-05-26 05:55:55 -07:00
local_info_t * dev = link - > priv ;
tuple_t tuple ;
cisparse_t parse ;
int last_fn , last_ret ;
u_char buf [ 64 ] ;
config_info_t conf ;
cistpl_cftable_entry_t dflt = { 0 } ;
DBG ( 0 , " sl811_cs_config(0x%p) \n " , link ) ;
/* Look up the current Vcc */
CS_CHECK ( GetConfigurationInfo ,
2006-03-31 17:21:06 +02:00
pcmcia_get_configuration_info ( link , & conf ) ) ;
2005-05-26 05:55:55 -07:00
2006-10-25 21:49:27 -04:00
tuple . Attributes = 0 ;
tuple . TupleData = buf ;
tuple . TupleDataMax = sizeof ( buf ) ;
tuple . TupleOffset = 0 ;
2005-05-26 05:55:55 -07:00
tuple . DesiredTuple = CISTPL_CFTABLE_ENTRY ;
2006-03-31 17:21:06 +02:00
CS_CHECK ( GetFirstTuple , pcmcia_get_first_tuple ( link , & tuple ) ) ;
2005-05-26 05:55:55 -07:00
while ( 1 ) {
cistpl_cftable_entry_t * cfg = & ( parse . cftable_entry ) ;
2006-03-31 17:21:06 +02:00
if ( pcmcia_get_tuple_data ( link , & tuple ) ! = 0
| | pcmcia_parse_tuple ( link , & tuple , & parse )
2005-05-26 05:55:55 -07:00
! = 0 )
goto next_entry ;
if ( cfg - > flags & CISTPL_CFTABLE_DEFAULT ) {
dflt = * cfg ;
}
if ( cfg - > index = = 0 )
goto next_entry ;
link - > conf . ConfigIndex = cfg - > index ;
/* Use power settings for Vcc and Vpp if present */
/* Note that the CIS values need to be rescaled */
if ( cfg - > vcc . present & ( 1 < < CISTPL_POWER_VNOM ) ) {
if ( cfg - > vcc . param [ CISTPL_POWER_VNOM ] / 10000
! = conf . Vcc )
goto next_entry ;
} else if ( dflt . vcc . present & ( 1 < < CISTPL_POWER_VNOM ) ) {
if ( dflt . vcc . param [ CISTPL_POWER_VNOM ] / 10000
! = conf . Vcc )
goto next_entry ;
}
if ( cfg - > vpp1 . present & ( 1 < < CISTPL_POWER_VNOM ) )
2006-01-15 12:43:16 +01:00
link - > conf . Vpp =
2005-05-26 05:55:55 -07:00
cfg - > vpp1 . param [ CISTPL_POWER_VNOM ] / 10000 ;
else if ( dflt . vpp1 . present & ( 1 < < CISTPL_POWER_VNOM ) )
2006-01-15 12:43:16 +01:00
link - > conf . Vpp =
2005-05-26 05:55:55 -07:00
dflt . vpp1 . param [ CISTPL_POWER_VNOM ] / 10000 ;
/* we need an interrupt */
if ( cfg - > irq . IRQInfo1 | | dflt . irq . IRQInfo1 )
link - > conf . Attributes | = CONF_ENABLE_IRQ ;
/* IO window settings */
link - > io . NumPorts1 = link - > io . NumPorts2 = 0 ;
if ( ( cfg - > io . nwin > 0 ) | | ( dflt . io . nwin > 0 ) ) {
cistpl_io_t * io = ( cfg - > io . nwin ) ? & cfg - > io : & dflt . io ;
link - > io . Attributes1 = IO_DATA_PATH_WIDTH_8 ;
link - > io . IOAddrLines = io - > flags & CISTPL_IO_LINES_MASK ;
link - > io . BasePort1 = io - > win [ 0 ] . base ;
link - > io . NumPorts1 = io - > win [ 0 ] . len ;
2006-03-31 17:21:06 +02:00
if ( pcmcia_request_io ( link , & link - > io ) ! = 0 )
2005-05-26 05:55:55 -07:00
goto next_entry ;
}
break ;
next_entry :
2006-03-31 17:21:06 +02:00
pcmcia_disable_device ( link ) ;
last_ret = pcmcia_get_next_tuple ( link , & tuple ) ;
2005-05-26 05:55:55 -07:00
}
/* require an IRQ and two registers */
if ( ! link - > io . NumPorts1 | | link - > io . NumPorts1 < 2 )
goto cs_failed ;
if ( link - > conf . Attributes & CONF_ENABLE_IRQ )
CS_CHECK ( RequestIRQ ,
2006-03-31 17:21:06 +02:00
pcmcia_request_irq ( link , & link - > irq ) ) ;
2005-05-26 05:55:55 -07:00
else
goto cs_failed ;
CS_CHECK ( RequestConfiguration ,
2006-03-31 17:21:06 +02:00
pcmcia_request_configuration ( link , & link - > conf ) ) ;
2005-05-26 05:55:55 -07:00
sprintf ( dev - > node . dev_name , driver_name ) ;
dev - > node . major = dev - > node . minor = 0 ;
2006-03-05 10:45:09 +01:00
link - > dev_node = & dev - > node ;
2005-05-26 05:55:55 -07:00
2006-01-15 12:43:16 +01:00
printk ( KERN_INFO " %s: index 0x%02x: " ,
dev - > node . dev_name , link - > conf . ConfigIndex ) ;
if ( link - > conf . Vpp )
printk ( " , Vpp %d.%d " , link - > conf . Vpp / 10 , link - > conf . Vpp % 10 ) ;
2005-05-26 05:55:55 -07:00
printk ( " , irq %d " , link - > irq . AssignedIRQ ) ;
printk ( " , io 0x%04x-0x%04x " , link - > io . BasePort1 ,
link - > io . BasePort1 + link - > io . NumPorts1 - 1 ) ;
printk ( " \n " ) ;
if ( sl811_hc_init ( parent , link - > io . BasePort1 , link - > irq . AssignedIRQ )
< 0 ) {
cs_failed :
printk ( " sl811_cs_config failed \n " ) ;
2006-03-31 17:21:06 +02:00
cs_error ( link , last_fn , last_ret ) ;
2005-05-26 05:55:55 -07:00
sl811_cs_release ( link ) ;
2006-03-31 17:26:06 +02:00
return - ENODEV ;
2005-05-26 05:55:55 -07:00
}
2006-03-31 17:26:06 +02:00
return 0 ;
2005-05-26 05:55:55 -07:00
}
2006-03-31 17:26:06 +02:00
static int sl811_cs_probe ( struct pcmcia_device * link )
2005-05-26 05:55:55 -07:00
{
local_info_t * local ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 01:49:03 -07:00
local = kzalloc ( sizeof ( local_info_t ) , GFP_KERNEL ) ;
2005-05-26 05:55:55 -07:00
if ( ! local )
2005-11-14 21:25:51 +01:00
return - ENOMEM ;
2006-03-31 17:21:06 +02:00
local - > p_dev = link ;
2005-05-26 05:55:55 -07:00
link - > priv = local ;
/* Initialize */
link - > irq . Attributes = IRQ_TYPE_EXCLUSIVE ;
link - > irq . IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID ;
link - > irq . Handler = NULL ;
link - > conf . Attributes = 0 ;
link - > conf . IntType = INT_MEMORY_AND_IO ;
2006-03-31 17:26:06 +02:00
return sl811_cs_config ( link ) ;
2005-05-26 05:55:55 -07:00
}
2005-06-27 16:28:43 -07:00
static struct pcmcia_device_id sl811_ids [ ] = {
PCMCIA_DEVICE_MANF_CARD ( 0xc015 , 0x0001 ) , /* RATOC USB HOST CF+ Card */
PCMCIA_DEVICE_NULL ,
} ;
MODULE_DEVICE_TABLE ( pcmcia , sl811_ids ) ;
2005-05-26 05:55:55 -07:00
static struct pcmcia_driver sl811_cs_driver = {
. owner = THIS_MODULE ,
. drv = {
. name = ( char * ) driver_name ,
} ,
2006-03-31 17:26:06 +02:00
. probe = sl811_cs_probe ,
2005-11-14 21:23:14 +01:00
. remove = sl811_cs_detach ,
2005-06-27 16:28:43 -07:00
. id_table = sl811_ids ,
2005-05-26 05:55:55 -07:00
} ;
/*====================================================================*/
static int __init init_sl811_cs ( void )
{
return pcmcia_register_driver ( & sl811_cs_driver ) ;
}
module_init ( init_sl811_cs ) ;
static void __exit exit_sl811_cs ( void )
{
pcmcia_unregister_driver ( & sl811_cs_driver ) ;
}
module_exit ( exit_sl811_cs ) ;