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