sl811_cs.c revision a0c53f1dca10acc93462339cbd0bf24b10d60a13
1c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/* 2c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * PCMCIA driver for SL811HS (as found in REX-CFU1U) 3c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Filename: sl811_cs.c 4c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Author: Yukio Yamamoto 5c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * 6c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Port to sl811-hcd and 2.6.x by 7c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Botond Botyanszki <boti@rocketmail.com> 8c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Simon Pickering 9c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * 10c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell * Last update: 2005-05-12 11c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell */ 12c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 13c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/kernel.h> 14c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/module.h> 15c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/init.h> 16c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/sched.h> 17c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/ptrace.h> 18c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/slab.h> 19c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/string.h> 20c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/timer.h> 21c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/ioport.h> 22d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 23c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 24c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <pcmcia/cs_types.h> 25c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <pcmcia/cs.h> 26c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <pcmcia/cistpl.h> 27c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <pcmcia/cisreg.h> 28c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <pcmcia/ds.h> 29c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 30c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#include <linux/usb_sl811.h> 31c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 32c6de2b64eb575a3f9326969ec5fcdc6032b38e42David BrownellMODULE_AUTHOR("Botond Botyanszki"); 33c6de2b64eb575a3f9326969ec5fcdc6032b38e42David BrownellMODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); 34c6de2b64eb575a3f9326969ec5fcdc6032b38e42David BrownellMODULE_LICENSE("GPL"); 35c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 36c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 37c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 38c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/* MACROS */ 39c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 40c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 41c9a50cc9318772e62d56f2a9172bdfda72bdacbeDavid Brownell#if defined(DEBUG) || defined(PCMCIA_DEBUG) 42c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 43c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic int pc_debug = 0; 44c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellmodule_param(pc_debug, int, 0644); 45c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 46c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args) 47c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 48c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#else 49c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#define DBG(n, args...) do{}while(0) 50c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#endif /* no debugging */ 51c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 52c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#define INFO(args...) printk(KERN_INFO "sl811_cs: " args) 53c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 54c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) 55c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 56c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell#define CS_CHECK(fn, ret) \ 57c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell do { \ 58c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell last_fn = (fn); \ 59c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if ((last_ret = (ret)) != 0) \ 60c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto cs_failed; \ 61c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } while (0) 62c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 63c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 64c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/* VARIABLES */ 65c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 66c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 67c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic const char driver_name[DEV_NAME_LEN] = "sl811_cs"; 68c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 69c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownelltypedef struct local_info_t { 70c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev_link_t link; 71c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev_node_t node; 72c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} local_info_t; 73c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 74cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void sl811_cs_release(dev_link_t * link); 75cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski 76c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 77c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 78c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic void release_platform_dev(struct device * dev) 79c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 80c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell DBG(0, "sl811_cs platform_dev release\n"); 81c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev->parent = NULL; 82c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 83c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 84c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic struct sl811_platform_data platform_data = { 85c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .potpg = 100, 86c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .power = 50, /* == 100mA */ 87c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell // .reset = ... FIXME: invoke CF reset on the card 88c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell}; 89c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 90c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic struct resource resources[] = { 91c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell [0] = { 92c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .flags = IORESOURCE_IRQ, 93c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell }, 94c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell [1] = { 95c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell // .name = "address", 96c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .flags = IORESOURCE_IO, 97c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell }, 98c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell [2] = { 99c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell // .name = "data", 100c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .flags = IORESOURCE_IO, 101c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell }, 102c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell}; 103c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 104a0c53f1dca10acc93462339cbd0bf24b10d60a13David Brownellextern struct platform_driver sl811h_driver; 105c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 106c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic struct platform_device platform_dev = { 107c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .id = -1, 108c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .dev = { 109c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .platform_data = &platform_data, 110c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .release = release_platform_dev, 111c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell }, 112c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .resource = resources, 113c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .num_resources = ARRAY_SIZE(resources), 114c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell}; 115c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 116c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq) 117c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 118c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (platform_dev.dev.parent) 119c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell return -EBUSY; 120c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell platform_dev.dev.parent = parent; 121c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 122c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* finish seting up the platform device */ 123c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell resources[0].start = irq; 124c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 125c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell resources[1].start = base_addr; 126c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell resources[1].end = base_addr; 127c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 128c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell resources[2].start = base_addr + 1; 129c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell resources[2].end = base_addr + 1; 130c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 131c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* The driver core will probe for us. We know sl811-hcd has been 132c9a50cc9318772e62d56f2a9172bdfda72bdacbeDavid Brownell * initialized already because of the link order dependency created 133c9a50cc9318772e62d56f2a9172bdfda72bdacbeDavid Brownell * by referencing "sl811h_driver". 134c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell */ 135a0c53f1dca10acc93462339cbd0bf24b10d60a13David Brownell platform_dev.name = sl811h_driver.driver.name; 136c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell return platform_device_register(&platform_dev); 137c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 138c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 139c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 140c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 141cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void sl811_cs_detach(struct pcmcia_device *p_dev) 142c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 143cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski dev_link_t *link = dev_to_instance(p_dev); 144c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 145c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell DBG(0, "sl811_cs_detach(0x%p)\n", link); 146c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 147cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski link->state &= ~DEV_PRESENT; 148cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski if (link->state & DEV_CONFIG) 149cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski sl811_cs_release(link); 150c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 151c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* This points to the parent local_info_t struct */ 152c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell kfree(link->priv); 153c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 154c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 155c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic void sl811_cs_release(dev_link_t * link) 156c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 157c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 158c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell DBG(0, "sl811_cs_release(0x%p)\n", link); 159c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 160c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Unlink the device chain */ 161c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->dev = NULL; 162c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 163c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell platform_device_unregister(&platform_dev); 164c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_release_configuration(link->handle); 165c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (link->io.NumPorts1) 166c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_release_io(link->handle, &link->io); 167c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (link->irq.AssignedIRQ) 168c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_release_irq(link->handle, &link->irq); 169c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->state &= ~DEV_CONFIG; 170c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 171c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 172c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic void sl811_cs_config(dev_link_t *link) 173c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 174c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell client_handle_t handle = link->handle; 175c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell struct device *parent = &handle_to_dev(handle); 176c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell local_info_t *dev = link->priv; 177c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple_t tuple; 178c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cisparse_t parse; 179c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell int last_fn, last_ret; 180c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell u_char buf[64]; 181c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell config_info_t conf; 182c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cistpl_cftable_entry_t dflt = { 0 }; 183c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 184c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell DBG(0, "sl811_cs_config(0x%p)\n", link); 185c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 186c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.DesiredTuple = CISTPL_CONFIG; 187c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.Attributes = 0; 188c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.TupleData = buf; 189c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.TupleDataMax = sizeof(buf); 190c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.TupleOffset = 0; 191c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); 192c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); 193c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); 194c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.ConfigBase = parse.config.base; 195c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Present = parse.config.rmask[0]; 196c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 197c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Configure card */ 198c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->state |= DEV_CONFIG; 199c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 200c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Look up the current Vcc */ 201c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(GetConfigurationInfo, 202c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_get_configuration_info(handle, &conf)); 203c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Vcc = conf.Vcc; 204c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 205c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 206c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); 207c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell while (1) { 208c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); 209c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 210c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (pcmcia_get_tuple_data(handle, &tuple) != 0 211c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell || pcmcia_parse_tuple(handle, &tuple, &parse) 212c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell != 0) 213c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto next_entry; 214c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 215c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { 216c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dflt = *cfg; 217c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } 218c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 219c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->index == 0) 220c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto next_entry; 221c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 222c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.ConfigIndex = cfg->index; 223c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 224c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Use power settings for Vcc and Vpp if present */ 225c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Note that the CIS values need to be rescaled */ 226c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { 227c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 228c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell != conf.Vcc) 229c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto next_entry; 230c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { 231c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000 232c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell != conf.Vcc) 233c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto next_entry; 234c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } 235c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 236c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) 237c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Vpp1 = link->conf.Vpp2 = 238c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; 239c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) 240c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Vpp1 = link->conf.Vpp2 = 241c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; 242c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 243c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* we need an interrupt */ 244c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) 245c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Attributes |= CONF_ENABLE_IRQ; 246c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 247c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* IO window settings */ 248c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.NumPorts1 = link->io.NumPorts2 = 0; 249c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { 250c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; 251c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 252c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 253c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; 254c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.BasePort1 = io->win[0].base; 255c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.NumPorts1 = io->win[0].len; 256c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 257c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (pcmcia_request_io(link->handle, &link->io) != 0) 258c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto next_entry; 259c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } 260c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell break; 261c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 262c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellnext_entry: 263c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (link->io.NumPorts1) 264c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_release_io(link->handle, &link->io); 265c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell last_ret = pcmcia_get_next_tuple(handle, &tuple); 266c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } 267c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 268c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* require an IRQ and two registers */ 269c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (!link->io.NumPorts1 || link->io.NumPorts1 < 2) 270c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto cs_failed; 271c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (link->conf.Attributes & CONF_ENABLE_IRQ) 272c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(RequestIRQ, 273c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_request_irq(link->handle, &link->irq)); 274c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell else 275c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell goto cs_failed; 276c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 277c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell CS_CHECK(RequestConfiguration, 278c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_request_configuration(link->handle, &link->conf)); 279c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 280c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell sprintf(dev->node.dev_name, driver_name); 281c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev->node.major = dev->node.minor = 0; 282c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->dev = &dev->node; 283c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 284c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", 285c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev->node.dev_name, link->conf.ConfigIndex, 286c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Vcc/10, link->conf.Vcc%10); 287c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (link->conf.Vpp1) 288c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); 289c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk(", irq %d", link->irq.AssignedIRQ); 290c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk(", io 0x%04x-0x%04x", link->io.BasePort1, 291c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->io.BasePort1+link->io.NumPorts1-1); 292c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk("\n"); 293c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 294c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->state &= ~DEV_CONFIG_PENDING; 295c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 296c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ) 297c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell < 0) { 298c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellcs_failed: 299c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell printk("sl811_cs_config failed\n"); 300c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell cs_error(link->handle, last_fn, last_ret); 301c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell sl811_cs_release(link); 302c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->state &= ~DEV_CONFIG_PENDING; 303c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell } 304c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 305c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 30698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowskistatic int sl811_suspend(struct pcmcia_device *dev) 30798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 30898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski dev_link_t *link = dev_to_instance(dev); 30998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 31098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski link->state |= DEV_SUSPEND; 31198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski if (link->state & DEV_CONFIG) 31298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski pcmcia_release_configuration(link->handle); 31398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 31498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 31598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 31698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 31798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowskistatic int sl811_resume(struct pcmcia_device *dev) 31898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 31998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski dev_link_t *link = dev_to_instance(dev); 32098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 32198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski link->state &= ~DEV_SUSPEND; 32298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski if (link->state & DEV_CONFIG) 32398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski pcmcia_request_configuration(link->handle, &link->conf); 32498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 32598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 32698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 32798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 328f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowskistatic int sl811_cs_attach(struct pcmcia_device *p_dev) 329c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 330c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell local_info_t *local; 331c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell dev_link_t *link; 332c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 333c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell local = kmalloc(sizeof(local_info_t), GFP_KERNEL); 334c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell if (!local) 335f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski return -ENOMEM; 336c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell memset(local, 0, sizeof(local_info_t)); 337c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link = &local->link; 338c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->priv = local; 339c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 340c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell /* Initialize */ 341c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 342c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; 343c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->irq.Handler = NULL; 344c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 345c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Attributes = 0; 346c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.Vcc = 33; 347c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell link->conf.IntType = INT_MEMORY_AND_IO; 348c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 349f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski link->handle = p_dev; 350f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski p_dev->instance = link; 351c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 352f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; 353f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski sl811_cs_config(link); 354f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski 355f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski return 0; 356c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 357c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 35822f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownellstatic struct pcmcia_device_id sl811_ids[] = { 35922f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownell PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ 36022f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownell PCMCIA_DEVICE_NULL, 36122f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownell}; 36222f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid BrownellMODULE_DEVICE_TABLE(pcmcia, sl811_ids); 36322f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownell 364c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic struct pcmcia_driver sl811_cs_driver = { 365c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .owner = THIS_MODULE, 366c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .drv = { 367c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell .name = (char *)driver_name, 368c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell }, 369f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski .probe = sl811_cs_attach, 370cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski .remove = sl811_cs_detach, 37122f3a8f5fc94be4dd31c4c5ec1d1dc2b9c83a8acDavid Brownell .id_table = sl811_ids, 37298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .suspend = sl811_suspend, 37398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .resume = sl811_resume, 374c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell}; 375c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 376c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell/*====================================================================*/ 377c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 378c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic int __init init_sl811_cs(void) 379c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 380c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell return pcmcia_register_driver(&sl811_cs_driver); 381c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 382c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellmodule_init(init_sl811_cs); 383c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell 384c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellstatic void __exit exit_sl811_cs(void) 385c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell{ 386c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell pcmcia_unregister_driver(&sl811_cs_driver); 387c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownell} 388c6de2b64eb575a3f9326969ec5fcdc6032b38e42David Brownellmodule_exit(exit_sl811_cs); 389