|  | /*====================================================================== | 
|  |  | 
|  | A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards. | 
|  |  | 
|  | This driver supports the Adaptec AHA-1460, the New Media Bus | 
|  | Toaster, and the New Media Toast & Jam. | 
|  |  | 
|  | aha152x_cs.c 1.54 2000/06/12 21:27:25 | 
|  |  | 
|  | The contents of this file are subject to the Mozilla Public | 
|  | License Version 1.1 (the "License"); you may not use this file | 
|  | except in compliance with the License. You may obtain a copy of | 
|  | the License at http://www.mozilla.org/MPL/ | 
|  |  | 
|  | Software distributed under the License is distributed on an "AS | 
|  | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | 
|  | implied. See the License for the specific language governing | 
|  | rights and limitations under the License. | 
|  |  | 
|  | 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. | 
|  |  | 
|  | Alternatively, the contents of this file may be used under the | 
|  | terms of the GNU General Public License version 2 (the "GPL"), in which | 
|  | case the provisions of the GPL are applicable instead of the | 
|  | above.  If you wish to allow the use of your version of this file | 
|  | only under the terms of the GPL and not to allow others to use | 
|  | your version of this file under the MPL, indicate your decision | 
|  | by deleting the provisions above and replace them with the notice | 
|  | and other provisions required by the GPL.  If you do not delete | 
|  | the provisions above, a recipient may use your version of this | 
|  | file under either the MPL or the GPL. | 
|  |  | 
|  | ======================================================================*/ | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/string.h> | 
|  | #include <linux/ioport.h> | 
|  | #include <scsi/scsi.h> | 
|  | #include <linux/major.h> | 
|  | #include <linux/blkdev.h> | 
|  | #include <scsi/scsi_ioctl.h> | 
|  |  | 
|  | #include "scsi.h" | 
|  | #include <scsi/scsi_host.h> | 
|  | #include "aha152x.h" | 
|  |  | 
|  | #include <pcmcia/cistpl.h> | 
|  | #include <pcmcia/ds.h> | 
|  |  | 
|  |  | 
|  | /*====================================================================*/ | 
|  |  | 
|  | /* Parameters that can be set with 'insmod' */ | 
|  |  | 
|  | /* SCSI bus setup options */ | 
|  | static int host_id = 7; | 
|  | static int reconnect = 1; | 
|  | static int parity = 1; | 
|  | static int synchronous = 1; | 
|  | static int reset_delay = 100; | 
|  | static int ext_trans = 0; | 
|  |  | 
|  | module_param(host_id, int, 0); | 
|  | module_param(reconnect, int, 0); | 
|  | module_param(parity, int, 0); | 
|  | module_param(synchronous, int, 0); | 
|  | module_param(reset_delay, int, 0); | 
|  | module_param(ext_trans, int, 0); | 
|  |  | 
|  | MODULE_LICENSE("Dual MPL/GPL"); | 
|  |  | 
|  | /*====================================================================*/ | 
|  |  | 
|  | typedef struct scsi_info_t { | 
|  | struct pcmcia_device	*p_dev; | 
|  | struct Scsi_Host	*host; | 
|  | } scsi_info_t; | 
|  |  | 
|  | static void aha152x_release_cs(struct pcmcia_device *link); | 
|  | static void aha152x_detach(struct pcmcia_device *p_dev); | 
|  | static int aha152x_config_cs(struct pcmcia_device *link); | 
|  |  | 
|  | static int aha152x_probe(struct pcmcia_device *link) | 
|  | { | 
|  | scsi_info_t *info; | 
|  |  | 
|  | dev_dbg(&link->dev, "aha152x_attach()\n"); | 
|  |  | 
|  | /* Create new SCSI device */ | 
|  | info = kzalloc(sizeof(*info), GFP_KERNEL); | 
|  | if (!info) return -ENOMEM; | 
|  | info->p_dev = link; | 
|  | link->priv = info; | 
|  |  | 
|  | link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; | 
|  | link->config_regs = PRESENT_OPTION; | 
|  |  | 
|  | return aha152x_config_cs(link); | 
|  | } /* aha152x_attach */ | 
|  |  | 
|  | /*====================================================================*/ | 
|  |  | 
|  | static void aha152x_detach(struct pcmcia_device *link) | 
|  | { | 
|  | dev_dbg(&link->dev, "aha152x_detach\n"); | 
|  |  | 
|  | aha152x_release_cs(link); | 
|  |  | 
|  | /* Unlink device structure, free bits */ | 
|  | kfree(link->priv); | 
|  | } /* aha152x_detach */ | 
|  |  | 
|  | /*====================================================================*/ | 
|  |  | 
|  | static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data) | 
|  | { | 
|  | p_dev->io_lines = 10; | 
|  |  | 
|  | /* For New Media T&J, look for a SCSI window */ | 
|  | if ((p_dev->resource[0]->end < 0x20) && | 
|  | (p_dev->resource[1]->end >= 0x20)) | 
|  | p_dev->resource[0]->start = p_dev->resource[1]->start; | 
|  |  | 
|  | if (p_dev->resource[0]->start >= 0xffff) | 
|  | return -EINVAL; | 
|  |  | 
|  | p_dev->resource[1]->start = p_dev->resource[1]->end = 0; | 
|  | p_dev->resource[0]->end = 0x20; | 
|  | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; | 
|  | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; | 
|  |  | 
|  | return pcmcia_request_io(p_dev); | 
|  | } | 
|  |  | 
|  | static int aha152x_config_cs(struct pcmcia_device *link) | 
|  | { | 
|  | scsi_info_t *info = link->priv; | 
|  | struct aha152x_setup s; | 
|  | int ret; | 
|  | struct Scsi_Host *host; | 
|  |  | 
|  | dev_dbg(&link->dev, "aha152x_config\n"); | 
|  |  | 
|  | ret = pcmcia_loop_config(link, aha152x_config_check, NULL); | 
|  | if (ret) | 
|  | goto failed; | 
|  |  | 
|  | if (!link->irq) | 
|  | goto failed; | 
|  |  | 
|  | ret = pcmcia_enable_device(link); | 
|  | if (ret) | 
|  | goto failed; | 
|  |  | 
|  | /* Set configuration options for the aha152x driver */ | 
|  | memset(&s, 0, sizeof(s)); | 
|  | s.conf        = "PCMCIA setup"; | 
|  | s.io_port     = link->resource[0]->start; | 
|  | s.irq         = link->irq; | 
|  | s.scsiid      = host_id; | 
|  | s.reconnect   = reconnect; | 
|  | s.parity      = parity; | 
|  | s.synchronous = synchronous; | 
|  | s.delay       = reset_delay; | 
|  | if (ext_trans) | 
|  | s.ext_trans = ext_trans; | 
|  |  | 
|  | host = aha152x_probe_one(&s); | 
|  | if (host == NULL) { | 
|  | printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | info->host = host; | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | failed: | 
|  | aha152x_release_cs(link); | 
|  | return -ENODEV; | 
|  | } | 
|  |  | 
|  | static void aha152x_release_cs(struct pcmcia_device *link) | 
|  | { | 
|  | scsi_info_t *info = link->priv; | 
|  |  | 
|  | aha152x_release(info->host); | 
|  | pcmcia_disable_device(link); | 
|  | } | 
|  |  | 
|  | static int aha152x_resume(struct pcmcia_device *link) | 
|  | { | 
|  | scsi_info_t *info = link->priv; | 
|  |  | 
|  | aha152x_host_reset_host(info->host); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct pcmcia_device_id aha152x_ids[] = { | 
|  | PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e), | 
|  | PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e), | 
|  | PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20), | 
|  | PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c), | 
|  | PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b), | 
|  | PCMCIA_DEVICE_NULL, | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(pcmcia, aha152x_ids); | 
|  |  | 
|  | static struct pcmcia_driver aha152x_cs_driver = { | 
|  | .owner		= THIS_MODULE, | 
|  | .name		= "aha152x_cs", | 
|  | .probe		= aha152x_probe, | 
|  | .remove		= aha152x_detach, | 
|  | .id_table       = aha152x_ids, | 
|  | .resume		= aha152x_resume, | 
|  | }; | 
|  |  | 
|  | static int __init init_aha152x_cs(void) | 
|  | { | 
|  | return pcmcia_register_driver(&aha152x_cs_driver); | 
|  | } | 
|  |  | 
|  | static void __exit exit_aha152x_cs(void) | 
|  | { | 
|  | pcmcia_unregister_driver(&aha152x_cs_driver); | 
|  | } | 
|  |  | 
|  | module_init(init_aha152x_cs); | 
|  | module_exit(exit_aha152x_cs); |