Merge remote branch 'alsa/fixes' into fix/hda
[pandora-kernel.git] / drivers / scsi / pcmcia / qlogic_stub.c
1 /*======================================================================
2
3     A driver for the Qlogic SCSI card
4
5     qlogic_cs.c 1.79 2000/06/12 21:27:26
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 which
23     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 <asm/io.h>
41 #include <scsi/scsi.h>
42 #include <linux/major.h>
43 #include <linux/blkdev.h>
44 #include <scsi/scsi_ioctl.h>
45 #include <linux/interrupt.h>
46
47 #include "scsi.h"
48 #include <scsi/scsi_host.h>
49 #include "../qlogicfas408.h"
50
51 #include <pcmcia/cs_types.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/cistpl.h>
54 #include <pcmcia/ds.h>
55 #include <pcmcia/ciscode.h>
56
57 /* Set the following to 2 to use normal interrupt (active high/totempole-
58  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
59  * drain
60  */
61 #define INT_TYPE        0
62
63 static char qlogic_name[] = "qlogic_cs";
64
65 static struct scsi_host_template qlogicfas_driver_template = {
66         .module                 = THIS_MODULE,
67         .name                   = qlogic_name,
68         .proc_name              = qlogic_name,
69         .info                   = qlogicfas408_info,
70         .queuecommand           = qlogicfas408_queuecommand,
71         .eh_abort_handler       = qlogicfas408_abort,
72         .eh_bus_reset_handler   = qlogicfas408_bus_reset,
73         .bios_param             = qlogicfas408_biosparam,
74         .can_queue              = 1,
75         .this_id                = -1,
76         .sg_tablesize           = SG_ALL,
77         .cmd_per_lun            = 1,
78         .use_clustering         = DISABLE_CLUSTERING,
79 };
80
81 /*====================================================================*/
82
83 typedef struct scsi_info_t {
84         struct pcmcia_device    *p_dev;
85         dev_node_t node;
86         struct Scsi_Host *host;
87         unsigned short manf_id;
88 } scsi_info_t;
89
90 static void qlogic_release(struct pcmcia_device *link);
91 static void qlogic_detach(struct pcmcia_device *p_dev);
92 static int qlogic_config(struct pcmcia_device * link);
93
94 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
95                                 struct pcmcia_device *link, int qbase, int qlirq)
96 {
97         int qltyp;              /* type of chip */
98         int qinitid;
99         struct Scsi_Host *shost;        /* registered host structure */
100         struct qlogicfas408_priv *priv;
101
102         qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
103         qinitid = host->this_id;
104         if (qinitid < 0)
105                 qinitid = 7;    /* if no ID, use 7 */
106
107         qlogicfas408_setup(qbase, qinitid, INT_TYPE);
108
109         host->name = qlogic_name;
110         shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
111         if (!shost)
112                 goto err;
113         shost->io_port = qbase;
114         shost->n_io_port = 16;
115         shost->dma_channel = -1;
116         if (qlirq != -1)
117                 shost->irq = qlirq;
118
119         priv = get_priv_by_host(shost);
120         priv->qlirq = qlirq;
121         priv->qbase = qbase;
122         priv->qinitid = qinitid;
123         priv->shost = shost;
124         priv->int_type = INT_TYPE;                                      
125
126         if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
127                 goto free_scsi_host;
128
129         sprintf(priv->qinfo,
130                 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
131                 qltyp, qbase, qlirq, QL_TURBO_PDMA);
132
133         if (scsi_add_host(shost, NULL))
134                 goto free_interrupt;
135
136         scsi_scan_host(shost);
137
138         return shost;
139
140 free_interrupt:
141         free_irq(qlirq, shost);
142
143 free_scsi_host:
144         scsi_host_put(shost);
145         
146 err:
147         return NULL;
148 }
149 static int qlogic_probe(struct pcmcia_device *link)
150 {
151         scsi_info_t *info;
152
153         dev_dbg(&link->dev, "qlogic_attach()\n");
154
155         /* Create new SCSI device */
156         info = kzalloc(sizeof(*info), GFP_KERNEL);
157         if (!info)
158                 return -ENOMEM;
159         info->p_dev = link;
160         link->priv = info;
161         link->io.NumPorts1 = 16;
162         link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
163         link->io.IOAddrLines = 10;
164         link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
165         link->conf.Attributes = CONF_ENABLE_IRQ;
166         link->conf.IntType = INT_MEMORY_AND_IO;
167         link->conf.Present = PRESENT_OPTION;
168
169         return qlogic_config(link);
170 }                               /* qlogic_attach */
171
172 /*====================================================================*/
173
174 static void qlogic_detach(struct pcmcia_device *link)
175 {
176         dev_dbg(&link->dev, "qlogic_detach\n");
177
178         qlogic_release(link);
179         kfree(link->priv);
180
181 }                               /* qlogic_detach */
182
183 /*====================================================================*/
184
185 static int qlogic_config_check(struct pcmcia_device *p_dev,
186                                cistpl_cftable_entry_t *cfg,
187                                cistpl_cftable_entry_t *dflt,
188                                unsigned int vcc,
189                                void *priv_data)
190 {
191         p_dev->io.BasePort1 = cfg->io.win[0].base;
192         p_dev->io.NumPorts1 = cfg->io.win[0].len;
193
194         if (p_dev->io.BasePort1 == 0)
195                 return -ENODEV;
196
197         return pcmcia_request_io(p_dev, &p_dev->io);
198 }
199
200 static int qlogic_config(struct pcmcia_device * link)
201 {
202         scsi_info_t *info = link->priv;
203         int ret;
204         struct Scsi_Host *host;
205
206         dev_dbg(&link->dev, "qlogic_config\n");
207
208         ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
209         if (ret)
210                 goto failed;
211
212         ret = pcmcia_request_irq(link, &link->irq);
213         if (ret)
214                 goto failed;
215
216         ret = pcmcia_request_configuration(link, &link->conf);
217         if (ret)
218                 goto failed;
219
220         if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
221                 /* set ATAcmd */
222                 outb(0xb4, link->io.BasePort1 + 0xd);
223                 outb(0x24, link->io.BasePort1 + 0x9);
224                 outb(0x04, link->io.BasePort1 + 0xd);
225         }
226
227         /* The KXL-810AN has a bigger IO port window */
228         if (link->io.NumPorts1 == 32)
229                 host = qlogic_detect(&qlogicfas_driver_template, link,
230                         link->io.BasePort1 + 16, link->irq.AssignedIRQ);
231         else
232                 host = qlogic_detect(&qlogicfas_driver_template, link,
233                         link->io.BasePort1, link->irq.AssignedIRQ);
234         
235         if (!host) {
236                 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
237                 goto failed;
238         }
239
240         sprintf(info->node.dev_name, "scsi%d", host->host_no);
241         link->dev_node = &info->node;
242         info->host = host;
243
244         return 0;
245
246 failed:
247         pcmcia_disable_device(link);
248         return -ENODEV;
249 }                               /* qlogic_config */
250
251 /*====================================================================*/
252
253 static void qlogic_release(struct pcmcia_device *link)
254 {
255         scsi_info_t *info = link->priv;
256
257         dev_dbg(&link->dev, "qlogic_release\n");
258
259         scsi_remove_host(info->host);
260
261         free_irq(link->irq.AssignedIRQ, info->host);
262         pcmcia_disable_device(link);
263
264         scsi_host_put(info->host);
265 }
266
267 /*====================================================================*/
268
269 static int qlogic_resume(struct pcmcia_device *link)
270 {
271         scsi_info_t *info = link->priv;
272
273         pcmcia_request_configuration(link, &link->conf);
274         if ((info->manf_id == MANFID_MACNICA) ||
275             (info->manf_id == MANFID_PIONEER) ||
276             (info->manf_id == 0x0098)) {
277                 outb(0x80, link->io.BasePort1 + 0xd);
278                 outb(0x24, link->io.BasePort1 + 0x9);
279                 outb(0x04, link->io.BasePort1 + 0xd);
280         }
281         /* Ugggglllyyyy!!! */
282         qlogicfas408_bus_reset(NULL);
283
284         return 0;
285 }
286
287 static struct pcmcia_device_id qlogic_ids[] = {
288         PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
289         PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
290         PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
291         PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
292         PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
293         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
294         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
295         PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
296         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
297         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
298         PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
299         PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
300         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
301         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
302         /* these conflict with other cards! */
303         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
304         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
305         PCMCIA_DEVICE_NULL,
306 };
307 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
308
309 static struct pcmcia_driver qlogic_cs_driver = {
310         .owner          = THIS_MODULE,
311         .drv            = {
312         .name           = "qlogic_cs",
313         },
314         .probe          = qlogic_probe,
315         .remove         = qlogic_detach,
316         .id_table       = qlogic_ids,
317         .resume         = qlogic_resume,
318 };
319
320 static int __init init_qlogic_cs(void)
321 {
322         return pcmcia_register_driver(&qlogic_cs_driver);
323 }
324
325 static void __exit exit_qlogic_cs(void)
326 {
327         pcmcia_unregister_driver(&qlogic_cs_driver);
328 }
329
330 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
331 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
332 MODULE_LICENSE("GPL");
333 module_init(init_qlogic_cs);
334 module_exit(exit_qlogic_cs);