ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / cdrom / isp16.c
1 /* -- ISP16 cdrom detection and configuration
2  *
3  *    Copyright (c) 1995,1996 Eric van der Maarel <H.T.M.v.d.Maarel@marin.nl>
4  *
5  *    Version 0.6
6  *
7  *    History:
8  *    0.5 First release.
9  *        Was included in the sjcd and optcd cdrom drivers.
10  *    0.6 First "stand-alone" version.
11  *        Removed sound configuration.
12  *        Added "module" support.
13  *
14  *      9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
15  *                         Removed init_module & cleanup_module in favor of 
16  *                         module_init & module_exit.
17  *                         Torben Mathiasen <tmm@image.dk>
18  *
19  *    Detect cdrom interface on ISP16 sound card.
20  *    Configure cdrom interface.
21  *
22  *    Algorithm for the card with OPTi 82C928 taken
23  *    from the CDSETUP.SYS driver for MSDOS,
24  *    by OPTi Computers, version 2.03.
25  *    Algorithm for the card with OPTi 82C929 as communicated
26  *    to me by Vadim Model and Leo Spiekman.
27  *
28  *    This program is free software; you can redistribute it and/or modify
29  *    it under the terms of the GNU General Public License as published by
30  *    the Free Software Foundation; either version 2 of the License, or
31  *    (at your option) any later version.
32  *
33  *    This program is distributed in the hope that it will be useful,
34  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
35  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  *    GNU General Public License for more details.
37  *
38  *    You should have received a copy of the GNU General Public License
39  *    along with this program; if not, write to the Free Software
40  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41  *
42  */
43
44 #define ISP16_VERSION_MAJOR 0
45 #define ISP16_VERSION_MINOR 6
46
47 #include <linux/module.h>
48
49 #include <linux/fs.h>
50 #include <linux/kernel.h>
51 #include <linux/string.h>
52 #include <linux/ioport.h>
53 #include <linux/init.h>
54 #include <asm/io.h>
55 #include "isp16.h"
56
57 static short isp16_detect(void);
58 static short isp16_c928__detect(void);
59 static short isp16_c929__detect(void);
60 static short isp16_cdi_config(int base, u_char drive_type, int irq,
61                               int dma);
62 static short isp16_type;        /* dependent on type of interface card */
63 static u_char isp16_ctrl;
64 static u_short isp16_enable_port;
65
66 static int isp16_cdrom_base = ISP16_CDROM_IO_BASE;
67 static int isp16_cdrom_irq = ISP16_CDROM_IRQ;
68 static int isp16_cdrom_dma = ISP16_CDROM_DMA;
69 static char *isp16_cdrom_type = ISP16_CDROM_TYPE;
70
71 MODULE_PARM(isp16_cdrom_base, "i");
72 MODULE_PARM(isp16_cdrom_irq, "i");
73 MODULE_PARM(isp16_cdrom_dma, "i");
74 MODULE_PARM(isp16_cdrom_type, "s");
75
76 #ifdef MODULE
77 void isp16_exit(void);
78 #endif
79
80 #define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
81 #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
82
83 #ifndef MODULE
84
85 static int
86 __init isp16_setup(char *str)
87 {
88         int ints[4];
89
90         (void) get_options(str, ARRAY_SIZE(ints), ints);
91         if (ints[0] > 0)
92                 isp16_cdrom_base = ints[1];
93         if (ints[0] > 1)
94                 isp16_cdrom_irq = ints[2];
95         if (ints[0] > 2)
96                 isp16_cdrom_dma = ints[3];
97         if (str)
98                 isp16_cdrom_type = str;
99
100         return 1;
101 }
102
103 __setup("isp16=", isp16_setup);
104
105 #endif                          /* MODULE */
106
107 /*
108  *  ISP16 initialisation.
109  *
110  */
111 int __init isp16_init(void)
112 {
113         u_char expected_drive;
114
115         printk(KERN_INFO
116                "ISP16: configuration cdrom interface, version %d.%d.\n",
117                ISP16_VERSION_MAJOR, ISP16_VERSION_MINOR);
118
119         if (!strcmp(isp16_cdrom_type, "noisp16")) {
120                 printk("ISP16: no cdrom interface configured.\n");
121                 return (0);
122         }
123
124         if (check_region(ISP16_IO_BASE, ISP16_IO_SIZE)) {
125                 printk("ISP16: i/o ports already in use.\n");
126                 return (-EIO);
127         }
128
129         if ((isp16_type = isp16_detect()) < 0) {
130                 printk("ISP16: no cdrom interface found.\n");
131                 return (-EIO);
132         }
133
134         printk(KERN_INFO
135                "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n",
136                (isp16_type == 2) ? 9 : 8);
137
138         if (!strcmp(isp16_cdrom_type, "Sanyo"))
139                 expected_drive =
140                     (isp16_type ? ISP16_SANYO1 : ISP16_SANYO0);
141         else if (!strcmp(isp16_cdrom_type, "Sony"))
142                 expected_drive = ISP16_SONY;
143         else if (!strcmp(isp16_cdrom_type, "Panasonic"))
144                 expected_drive =
145                     (isp16_type ? ISP16_PANASONIC1 : ISP16_PANASONIC0);
146         else if (!strcmp(isp16_cdrom_type, "Mitsumi"))
147                 expected_drive = ISP16_MITSUMI;
148         else {
149                 printk("ISP16: %s not supported by cdrom interface.\n",
150                        isp16_cdrom_type);
151                 return (-EIO);
152         }
153
154         if (isp16_cdi_config(isp16_cdrom_base, expected_drive,
155                              isp16_cdrom_irq, isp16_cdrom_dma) < 0) {
156                 printk
157                     ("ISP16: cdrom interface has not been properly configured.\n");
158                 return (-EIO);
159         }
160         printk(KERN_INFO
161                "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d,"
162                " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq,
163                isp16_cdrom_dma, isp16_cdrom_type);
164         return (0);
165 }
166
167 static short __init isp16_detect(void)
168 {
169
170         if (isp16_c929__detect() >= 0)
171                 return (2);
172         else
173                 return (isp16_c928__detect());
174 }
175
176 static short __init isp16_c928__detect(void)
177 {
178         u_char ctrl;
179         u_char enable_cdrom;
180         u_char io;
181         short i = -1;
182
183         isp16_ctrl = ISP16_C928__CTRL;
184         isp16_enable_port = ISP16_C928__ENABLE_PORT;
185
186         /* read' and write' are a special read and write, respectively */
187
188         /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
189         ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC;
190         ISP16_OUT(ISP16_CTRL_PORT, ctrl);
191
192         /* read' 3,4 and 5-bit from the cdrom enable port */
193         enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38;
194
195         if (!(enable_cdrom & 0x20)) {   /* 5-bit not set */
196                 /* read' last 2 bits of ISP16_IO_SET_PORT */
197                 io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03;
198                 if (((io & 0x01) << 1) == (io & 0x02)) {        /* bits are the same */
199                         if (io == 0) {  /* ...the same and 0 */
200                                 i = 0;
201                                 enable_cdrom |= 0x20;
202                         } else {        /* ...the same and 1 *//* my card, first time 'round */
203                                 i = 1;
204                                 enable_cdrom |= 0x28;
205                         }
206                         ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom);
207                 } else {        /* bits are not the same */
208                         ISP16_OUT(ISP16_CTRL_PORT, ctrl);
209                         return (i);     /* -> not detected: possibly incorrect conclusion */
210                 }
211         } else if (enable_cdrom == 0x20)
212                 i = 0;
213         else if (enable_cdrom == 0x28)  /* my card, already initialised */
214                 i = 1;
215
216         ISP16_OUT(ISP16_CTRL_PORT, ctrl);
217
218         return (i);
219 }
220
221 static short __init isp16_c929__detect(void)
222 {
223         u_char ctrl;
224         u_char tmp;
225
226         isp16_ctrl = ISP16_C929__CTRL;
227         isp16_enable_port = ISP16_C929__ENABLE_PORT;
228
229         /* read' and write' are a special read and write, respectively */
230
231         /* read' ISP16_CTRL_PORT and save */
232         ctrl = ISP16_IN(ISP16_CTRL_PORT);
233
234         /* write' zero to the ctrl port and get response */
235         ISP16_OUT(ISP16_CTRL_PORT, 0);
236         tmp = ISP16_IN(ISP16_CTRL_PORT);
237
238         if (tmp != 2)           /* isp16 with 82C929 not detected */
239                 return (-1);
240
241         /* restore ctrl port value */
242         ISP16_OUT(ISP16_CTRL_PORT, ctrl);
243
244         return (2);
245 }
246
247 static short __init
248 isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
249 {
250         u_char base_code;
251         u_char irq_code;
252         u_char dma_code;
253         u_char i;
254
255         if ((drive_type == ISP16_MITSUMI) && (dma != 0))
256                 printk("ISP16: Mitsumi cdrom drive has no dma support.\n");
257
258         switch (base) {
259         case 0x340:
260                 base_code = ISP16_BASE_340;
261                 break;
262         case 0x330:
263                 base_code = ISP16_BASE_330;
264                 break;
265         case 0x360:
266                 base_code = ISP16_BASE_360;
267                 break;
268         case 0x320:
269                 base_code = ISP16_BASE_320;
270                 break;
271         default:
272                 printk
273                     ("ISP16: base address 0x%03X not supported by cdrom interface.\n",
274                      base);
275                 return (-1);
276         }
277         switch (irq) {
278         case 0:
279                 irq_code = ISP16_IRQ_X;
280                 break;          /* disable irq */
281         case 5:
282                 irq_code = ISP16_IRQ_5;
283                 printk("ISP16: irq 5 shouldn't be used by cdrom interface,"
284                        " due to possible conflicts with the sound card.\n");
285                 break;
286         case 7:
287                 irq_code = ISP16_IRQ_7;
288                 printk("ISP16: irq 7 shouldn't be used by cdrom interface,"
289                        " due to possible conflicts with the sound card.\n");
290                 break;
291         case 3:
292                 irq_code = ISP16_IRQ_3;
293                 break;
294         case 9:
295                 irq_code = ISP16_IRQ_9;
296                 break;
297         case 10:
298                 irq_code = ISP16_IRQ_10;
299                 break;
300         case 11:
301                 irq_code = ISP16_IRQ_11;
302                 break;
303         default:
304                 printk("ISP16: irq %d not supported by cdrom interface.\n",
305                        irq);
306                 return (-1);
307         }
308         switch (dma) {
309         case 0:
310                 dma_code = ISP16_DMA_X;
311                 break;          /* disable dma */
312         case 1:
313                 printk("ISP16: dma 1 cannot be used by cdrom interface,"
314                        " due to conflict with the sound card.\n");
315                 return (-1);
316                 break;
317         case 3:
318                 dma_code = ISP16_DMA_3;
319                 break;
320         case 5:
321                 dma_code = ISP16_DMA_5;
322                 break;
323         case 6:
324                 dma_code = ISP16_DMA_6;
325                 break;
326         case 7:
327                 dma_code = ISP16_DMA_7;
328                 break;
329         default:
330                 printk("ISP16: dma %d not supported by cdrom interface.\n",
331                        dma);
332                 return (-1);
333         }
334
335         if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
336             drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
337             drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
338             drive_type != ISP16_DRIVE_X) {
339                 printk
340                     ("ISP16: drive type (code 0x%02X) not supported by cdrom"
341                      " interface.\n", drive_type);
342                 return (-1);
343         }
344
345         /* set type of interface */
346         i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;      /* clear some bits */
347         ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type);
348
349         /* enable cdrom on interface with 82C929 chip */
350         if (isp16_type > 1)
351                 ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM);
352
353         /* set base address, irq and dma */
354         i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;    /* keep some bits */
355         ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code);
356
357         return (0);
358 }
359
360 void __exit isp16_exit(void)
361 {
362         release_region(ISP16_IO_BASE, ISP16_IO_SIZE);
363         printk(KERN_INFO "ISP16: module released.\n");
364 }
365
366 #ifdef MODULE
367 module_init(isp16_init);
368 #endif
369 module_exit(isp16_exit);
370
371 MODULE_LICENSE("GPL");