xref: /linux/drivers/scsi/pcmcia/aha152x_stub.c (revision 20d0021394c1b070bf04b22c5bc8fdb437edd4c5)
1 /*======================================================================
2 
3     A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
4 
5     This driver supports the Adaptec AHA-1460, the New Media Bus
6     Toaster, and the New Media Toast & Jam.
7 
8     aha152x_cs.c 1.54 2000/06/12 21:27:25
9 
10     The contents of this file are subject to the Mozilla Public
11     License Version 1.1 (the "License"); you may not use this file
12     except in compliance with the License. You may obtain a copy of
13     the License at http://www.mozilla.org/MPL/
14 
15     Software distributed under the License is distributed on an "AS
16     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17     implied. See the License for the specific language governing
18     rights and limitations under the License.
19 
20     The initial developer of the original code is David A. Hinds
21     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
22     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
23 
24     Alternatively, the contents of this file may be used under the
25     terms of the GNU General Public License version 2 (the "GPL"), in which
26     case the provisions of the GPL are applicable instead of the
27     above.  If you wish to allow the use of your version of this file
28     only under the terms of the GPL and not to allow others to use
29     your version of this file under the MPL, indicate your decision
30     by deleting the provisions above and replace them with the notice
31     and other provisions required by the GPL.  If you do not delete
32     the provisions above, a recipient may use your version of this
33     file under either the MPL or the GPL.
34 
35 ======================================================================*/
36 
37 #include <linux/module.h>
38 #include <linux/init.h>
39 #include <linux/kernel.h>
40 #include <linux/sched.h>
41 #include <linux/slab.h>
42 #include <linux/string.h>
43 #include <linux/ioport.h>
44 #include <scsi/scsi.h>
45 #include <linux/major.h>
46 #include <linux/blkdev.h>
47 #include <scsi/scsi_ioctl.h>
48 
49 #include "scsi.h"
50 #include <scsi/scsi_host.h>
51 #include "aha152x.h"
52 
53 #include <pcmcia/cs_types.h>
54 #include <pcmcia/cs.h>
55 #include <pcmcia/cistpl.h>
56 #include <pcmcia/ds.h>
57 
58 #ifdef PCMCIA_DEBUG
59 static int pc_debug = PCMCIA_DEBUG;
60 module_param(pc_debug, int, 0644);
61 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
62 static char *version =
63 "aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)";
64 #else
65 #define DEBUG(n, args...)
66 #endif
67 
68 /*====================================================================*/
69 
70 /* Parameters that can be set with 'insmod' */
71 
72 /* SCSI bus setup options */
73 static int host_id = 7;
74 static int reconnect = 1;
75 static int parity = 1;
76 static int synchronous = 1;
77 static int reset_delay = 100;
78 static int ext_trans = 0;
79 
80 module_param(host_id, int, 0);
81 module_param(reconnect, int, 0);
82 module_param(parity, int, 0);
83 module_param(synchronous, int, 0);
84 module_param(reset_delay, int, 0);
85 module_param(ext_trans, int, 0);
86 
87 MODULE_LICENSE("Dual MPL/GPL");
88 
89 /*====================================================================*/
90 
91 typedef struct scsi_info_t {
92     dev_link_t		link;
93     dev_node_t		node;
94     struct Scsi_Host	*host;
95 } scsi_info_t;
96 
97 static void aha152x_release_cs(dev_link_t *link);
98 static int aha152x_event(event_t event, int priority,
99 			 event_callback_args_t *args);
100 
101 static dev_link_t *aha152x_attach(void);
102 static void aha152x_detach(dev_link_t *);
103 
104 static dev_link_t *dev_list;
105 static dev_info_t dev_info = "aha152x_cs";
106 
107 static dev_link_t *aha152x_attach(void)
108 {
109     scsi_info_t *info;
110     client_reg_t client_reg;
111     dev_link_t *link;
112     int ret;
113 
114     DEBUG(0, "aha152x_attach()\n");
115 
116     /* Create new SCSI device */
117     info = kmalloc(sizeof(*info), GFP_KERNEL);
118     if (!info) return NULL;
119     memset(info, 0, sizeof(*info));
120     link = &info->link; link->priv = info;
121 
122     link->io.NumPorts1 = 0x20;
123     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
124     link->io.IOAddrLines = 10;
125     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
126     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
127     link->conf.Attributes = CONF_ENABLE_IRQ;
128     link->conf.Vcc = 50;
129     link->conf.IntType = INT_MEMORY_AND_IO;
130     link->conf.Present = PRESENT_OPTION;
131 
132     /* Register with Card Services */
133     link->next = dev_list;
134     dev_list = link;
135     client_reg.dev_info = &dev_info;
136     client_reg.Version = 0x0210;
137     client_reg.event_callback_args.client_data = link;
138     ret = pcmcia_register_client(&link->handle, &client_reg);
139     if (ret != 0) {
140 	cs_error(link->handle, RegisterClient, ret);
141 	aha152x_detach(link);
142 	return NULL;
143     }
144 
145     return link;
146 } /* aha152x_attach */
147 
148 /*====================================================================*/
149 
150 static void aha152x_detach(dev_link_t *link)
151 {
152     dev_link_t **linkp;
153 
154     DEBUG(0, "aha152x_detach(0x%p)\n", link);
155 
156     /* Locate device structure */
157     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
158 	if (*linkp == link) break;
159     if (*linkp == NULL)
160 	return;
161 
162     if (link->state & DEV_CONFIG)
163 	aha152x_release_cs(link);
164 
165     if (link->handle)
166 	pcmcia_deregister_client(link->handle);
167 
168     /* Unlink device structure, free bits */
169     *linkp = link->next;
170     kfree(link->priv);
171 
172 } /* aha152x_detach */
173 
174 /*====================================================================*/
175 
176 #define CS_CHECK(fn, ret) \
177 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
178 
179 static void aha152x_config_cs(dev_link_t *link)
180 {
181     client_handle_t handle = link->handle;
182     scsi_info_t *info = link->priv;
183     struct aha152x_setup s;
184     tuple_t tuple;
185     cisparse_t parse;
186     int i, last_ret, last_fn;
187     u_char tuple_data[64];
188     struct Scsi_Host *host;
189 
190     DEBUG(0, "aha152x_config(0x%p)\n", link);
191 
192     tuple.DesiredTuple = CISTPL_CONFIG;
193     tuple.TupleData = tuple_data;
194     tuple.TupleDataMax = 64;
195     tuple.TupleOffset = 0;
196     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
197     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
198     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
199     link->conf.ConfigBase = parse.config.base;
200 
201     /* Configure card */
202     link->state |= DEV_CONFIG;
203 
204     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
205     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
206     while (1) {
207 	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
208 		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
209 	    goto next_entry;
210 	/* For New Media T&J, look for a SCSI window */
211 	if (parse.cftable_entry.io.win[0].len >= 0x20)
212 	    link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
213 	else if ((parse.cftable_entry.io.nwin > 1) &&
214 		 (parse.cftable_entry.io.win[1].len >= 0x20))
215 	    link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
216 	if ((parse.cftable_entry.io.nwin > 0) &&
217 	    (link->io.BasePort1 < 0xffff)) {
218 	    link->conf.ConfigIndex = parse.cftable_entry.index;
219 	    i = pcmcia_request_io(handle, &link->io);
220 	    if (i == CS_SUCCESS) break;
221 	}
222     next_entry:
223 	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
224     }
225 
226     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
227     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
228 
229     /* Set configuration options for the aha152x driver */
230     memset(&s, 0, sizeof(s));
231     s.conf        = "PCMCIA setup";
232     s.io_port     = link->io.BasePort1;
233     s.irq         = link->irq.AssignedIRQ;
234     s.scsiid      = host_id;
235     s.reconnect   = reconnect;
236     s.parity      = parity;
237     s.synchronous = synchronous;
238     s.delay       = reset_delay;
239     if (ext_trans)
240         s.ext_trans = ext_trans;
241 
242     host = aha152x_probe_one(&s);
243     if (host == NULL) {
244 	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
245 	goto cs_failed;
246     }
247 
248     sprintf(info->node.dev_name, "scsi%d", host->host_no);
249     link->dev = &info->node;
250     info->host = host;
251 
252     link->state &= ~DEV_CONFIG_PENDING;
253     return;
254 
255 cs_failed:
256     cs_error(link->handle, last_fn, last_ret);
257     aha152x_release_cs(link);
258     return;
259 }
260 
261 static void aha152x_release_cs(dev_link_t *link)
262 {
263 	scsi_info_t *info = link->priv;
264 
265 	aha152x_release(info->host);
266 	link->dev = NULL;
267 
268 	pcmcia_release_configuration(link->handle);
269 	pcmcia_release_io(link->handle, &link->io);
270 	pcmcia_release_irq(link->handle, &link->irq);
271 
272 	link->state &= ~DEV_CONFIG;
273 }
274 
275 static int aha152x_event(event_t event, int priority,
276 			 event_callback_args_t *args)
277 {
278     dev_link_t *link = args->client_data;
279     scsi_info_t *info = link->priv;
280 
281     DEBUG(0, "aha152x_event(0x%06x)\n", event);
282 
283     switch (event) {
284     case CS_EVENT_CARD_REMOVAL:
285 	link->state &= ~DEV_PRESENT;
286 	if (link->state & DEV_CONFIG)
287 	    aha152x_release_cs(link);
288 	break;
289     case CS_EVENT_CARD_INSERTION:
290 	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
291 	aha152x_config_cs(link);
292 	break;
293     case CS_EVENT_PM_SUSPEND:
294 	link->state |= DEV_SUSPEND;
295 	/* Fall through... */
296     case CS_EVENT_RESET_PHYSICAL:
297 	if (link->state & DEV_CONFIG)
298 	    pcmcia_release_configuration(link->handle);
299 	break;
300     case CS_EVENT_PM_RESUME:
301 	link->state &= ~DEV_SUSPEND;
302 	/* Fall through... */
303     case CS_EVENT_CARD_RESET:
304 	if (link->state & DEV_CONFIG) {
305 	    Scsi_Cmnd tmp;
306 	    pcmcia_request_configuration(link->handle, &link->conf);
307 	    tmp.device->host = info->host;
308 	    aha152x_host_reset(&tmp);
309 	}
310 	break;
311     }
312     return 0;
313 }
314 
315 static struct pcmcia_device_id aha152x_ids[] = {
316 	PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
317 	PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
318 	PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
319 	PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
320 	PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
321 	PCMCIA_DEVICE_NULL,
322 };
323 MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
324 
325 static struct pcmcia_driver aha152x_cs_driver = {
326 	.owner		= THIS_MODULE,
327 	.drv		= {
328 		.name	= "aha152x_cs",
329 	},
330 	.attach		= aha152x_attach,
331 	.event		= aha152x_event,
332 	.detach		= aha152x_detach,
333 	.id_table       = aha152x_ids,
334 };
335 
336 static int __init init_aha152x_cs(void)
337 {
338 	return pcmcia_register_driver(&aha152x_cs_driver);
339 }
340 
341 static void __exit exit_aha152x_cs(void)
342 {
343 	pcmcia_unregister_driver(&aha152x_cs_driver);
344 	BUG_ON(dev_list != NULL);
345 }
346 
347 module_init(init_aha152x_cs);
348 module_exit(exit_aha152x_cs);
349 
350