1/*====================================================================== 2 3 A driver for Future Domain-compatible PCMCIA SCSI cards 4 5 fdomain_cs.c 1.47 2001/10/13 00:08:52 6 7 The contents of this file are subject to the Mozilla Public 8 License Version 1.1 (the "License"); you may not use this file 9 except in compliance with the License. You may obtain a copy of 10 the License at http://www.mozilla.org/MPL/ 11 12 Software distributed under the License is distributed on an "AS 13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 implied. See the License for the specific language governing 15 rights and limitations under the License. 16 17 The initial developer of the original code is David A. Hinds 18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 20 21 Alternatively, the contents of this file may be used under the 22 terms of the GNU General Public License version 2 (the "GPL"), in 23 which case the provisions of the GPL are applicable instead of the 24 above. If you wish to allow the use of your version of this file 25 only under the terms of the GPL and not to allow others to use 26 your version of this file under the MPL, indicate your decision 27 by deleting the provisions above and replace them with the notice 28 and other provisions required by the GPL. If you do not delete 29 the provisions above, a recipient may use your version of this 30 file under either the MPL or the GPL. 31 32======================================================================*/ 33 34#include <linux/module.h> 35#include <linux/init.h> 36#include <linux/kernel.h> 37#include <linux/slab.h> 38#include <linux/string.h> 39#include <linux/ioport.h> 40#include <scsi/scsi.h> 41#include <linux/major.h> 42#include <linux/blkdev.h> 43#include <scsi/scsi_ioctl.h> 44 45#include "scsi.h" 46#include <scsi/scsi_host.h> 47#include "fdomain.h" 48 49#include <pcmcia/cs_types.h> 50#include <pcmcia/cs.h> 51#include <pcmcia/cistpl.h> 52#include <pcmcia/ds.h> 53 54/*====================================================================*/ 55 56/* Module parameters */ 57 58MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 59MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); 60MODULE_LICENSE("Dual MPL/GPL"); 61 62#ifdef PCMCIA_DEBUG 63static int pc_debug = PCMCIA_DEBUG; 64module_param(pc_debug, int, 0); 65#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) 66static char *version = 67"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; 68#else 69#define DEBUG(n, args...) 70#endif 71 72/*====================================================================*/ 73 74typedef struct scsi_info_t { 75 struct pcmcia_device *p_dev; 76 dev_node_t node; 77 struct Scsi_Host *host; 78} scsi_info_t; 79 80 81static void fdomain_release(struct pcmcia_device *link); 82static void fdomain_detach(struct pcmcia_device *p_dev); 83static int fdomain_config(struct pcmcia_device *link); 84 85static int fdomain_probe(struct pcmcia_device *link) 86{ 87 scsi_info_t *info; 88 89 DEBUG(0, "fdomain_attach()\n"); 90 91 /* Create new SCSI device */ 92 info = kzalloc(sizeof(*info), GFP_KERNEL); 93 if (!info) 94 return -ENOMEM; 95 96 info->p_dev = link; 97 link->priv = info; 98 link->io.NumPorts1 = 0x10; 99 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 100 link->io.IOAddrLines = 10; 101 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 102 link->irq.IRQInfo1 = IRQ_LEVEL_ID; 103 link->conf.Attributes = CONF_ENABLE_IRQ; 104 link->conf.IntType = INT_MEMORY_AND_IO; 105 link->conf.Present = PRESENT_OPTION; 106 107 return fdomain_config(link); 108} /* fdomain_attach */ 109 110/*====================================================================*/ 111 112static void fdomain_detach(struct pcmcia_device *link) 113{ 114 DEBUG(0, "fdomain_detach(0x%p)\n", link); 115 116 fdomain_release(link); 117 118 kfree(link->priv); 119} /* fdomain_detach */ 120 121/*====================================================================*/ 122 123#define CS_CHECK(fn, ret) \ 124do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 125 126static int fdomain_config(struct pcmcia_device *link) 127{ 128 scsi_info_t *info = link->priv; 129 tuple_t tuple; 130 cisparse_t parse; 131 int i, last_ret, last_fn; 132 u_char tuple_data[64]; 133 char str[16]; 134 struct Scsi_Host *host; 135 136 DEBUG(0, "fdomain_config(0x%p)\n", link); 137 138 tuple.TupleData = tuple_data; 139 tuple.TupleDataMax = 64; 140 tuple.TupleOffset = 0; 141 142 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 143 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); 144 while (1) { 145 if (pcmcia_get_tuple_data(link, &tuple) != 0 || 146 pcmcia_parse_tuple(link, &tuple, &parse) != 0) 147 goto next_entry; 148 link->conf.ConfigIndex = parse.cftable_entry.index; 149 link->io.BasePort1 = parse.cftable_entry.io.win[0].base; 150 i = pcmcia_request_io(link, &link->io); 151 if (i == CS_SUCCESS) break; 152 next_entry: 153 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); 154 } 155 156 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); 157 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); 158 159 /* A bad hack... */ 160 release_region(link->io.BasePort1, link->io.NumPorts1); 161 162 /* Set configuration options for the fdomain driver */ 163 sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); 164 fdomain_setup(str); 165 166 host = __fdomain_16x0_detect(&fdomain_driver_template); 167 if (!host) { 168 printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); 169 goto cs_failed; 170 } 171 172 if (scsi_add_host(host, NULL)) 173 goto cs_failed; 174 scsi_scan_host(host); 175 176 sprintf(info->node.dev_name, "scsi%d", host->host_no); 177 link->dev_node = &info->node; 178 info->host = host; 179 180 return 0; 181 182cs_failed: 183 cs_error(link, last_fn, last_ret); 184 fdomain_release(link); 185 return -ENODEV; 186} /* fdomain_config */ 187 188/*====================================================================*/ 189 190static void fdomain_release(struct pcmcia_device *link) 191{ 192 scsi_info_t *info = link->priv; 193 194 DEBUG(0, "fdomain_release(0x%p)\n", link); 195 196 scsi_remove_host(info->host); 197 pcmcia_disable_device(link); 198 scsi_unregister(info->host); 199} 200 201/*====================================================================*/ 202 203static int fdomain_resume(struct pcmcia_device *link) 204{ 205 fdomain_16x0_bus_reset(NULL); 206 207 return 0; 208} 209 210static struct pcmcia_device_id fdomain_ids[] = { 211 PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20), 212 PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e), 213 PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f), 214 PCMCIA_DEVICE_NULL, 215}; 216MODULE_DEVICE_TABLE(pcmcia, fdomain_ids); 217 218static struct pcmcia_driver fdomain_cs_driver = { 219 .owner = THIS_MODULE, 220 .drv = { 221 .name = "fdomain_cs", 222 }, 223 .probe = fdomain_probe, 224 .remove = fdomain_detach, 225 .id_table = fdomain_ids, 226 .resume = fdomain_resume, 227}; 228 229static int __init init_fdomain_cs(void) 230{ 231 return pcmcia_register_driver(&fdomain_cs_driver); 232} 233 234static void __exit exit_fdomain_cs(void) 235{ 236 pcmcia_unregister_driver(&fdomain_cs_driver); 237} 238 239module_init(init_fdomain_cs); 240module_exit(exit_fdomain_cs); 241