diff options
Diffstat (limited to 'drivers/cdrom/isp16.c')
-rw-r--r-- | drivers/cdrom/isp16.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c new file mode 100644 index 000000000000..8e68d858ce64 --- /dev/null +++ b/drivers/cdrom/isp16.c | |||
@@ -0,0 +1,374 @@ | |||
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_param(isp16_cdrom_base, int, 0); | ||
76 | module_param(isp16_cdrom_irq, int, 0); | ||
77 | module_param(isp16_cdrom_dma, int, 0); | ||
78 | module_param(isp16_cdrom_type, charp, 0); | ||
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 | static 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 (!request_region(ISP16_IO_BASE, ISP16_IO_SIZE, "isp16")) { | ||
125 | printk("ISP16: i/o ports already in use.\n"); | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | if ((isp16_type = isp16_detect()) < 0) { | ||
130 | printk("ISP16: no cdrom interface found.\n"); | ||
131 | goto cleanup_out; | ||
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 | goto cleanup_out; | ||
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 | goto cleanup_out; | ||
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 | cleanup_out: | ||
167 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
168 | out: | ||
169 | return -EIO; | ||
170 | } | ||
171 | |||
172 | static short __init isp16_detect(void) | ||
173 | { | ||
174 | |||
175 | if (isp16_c929__detect() >= 0) | ||
176 | return 2; | ||
177 | else | ||
178 | return (isp16_c928__detect()); | ||
179 | } | ||
180 | |||
181 | static short __init isp16_c928__detect(void) | ||
182 | { | ||
183 | u_char ctrl; | ||
184 | u_char enable_cdrom; | ||
185 | u_char io; | ||
186 | short i = -1; | ||
187 | |||
188 | isp16_ctrl = ISP16_C928__CTRL; | ||
189 | isp16_enable_port = ISP16_C928__ENABLE_PORT; | ||
190 | |||
191 | /* read' and write' are a special read and write, respectively */ | ||
192 | |||
193 | /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ | ||
194 | ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC; | ||
195 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
196 | |||
197 | /* read' 3,4 and 5-bit from the cdrom enable port */ | ||
198 | enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38; | ||
199 | |||
200 | if (!(enable_cdrom & 0x20)) { /* 5-bit not set */ | ||
201 | /* read' last 2 bits of ISP16_IO_SET_PORT */ | ||
202 | io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03; | ||
203 | if (((io & 0x01) << 1) == (io & 0x02)) { /* bits are the same */ | ||
204 | if (io == 0) { /* ...the same and 0 */ | ||
205 | i = 0; | ||
206 | enable_cdrom |= 0x20; | ||
207 | } else { /* ...the same and 1 *//* my card, first time 'round */ | ||
208 | i = 1; | ||
209 | enable_cdrom |= 0x28; | ||
210 | } | ||
211 | ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom); | ||
212 | } else { /* bits are not the same */ | ||
213 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
214 | return i; /* -> not detected: possibly incorrect conclusion */ | ||
215 | } | ||
216 | } else if (enable_cdrom == 0x20) | ||
217 | i = 0; | ||
218 | else if (enable_cdrom == 0x28) /* my card, already initialised */ | ||
219 | i = 1; | ||
220 | |||
221 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
222 | |||
223 | return i; | ||
224 | } | ||
225 | |||
226 | static short __init isp16_c929__detect(void) | ||
227 | { | ||
228 | u_char ctrl; | ||
229 | u_char tmp; | ||
230 | |||
231 | isp16_ctrl = ISP16_C929__CTRL; | ||
232 | isp16_enable_port = ISP16_C929__ENABLE_PORT; | ||
233 | |||
234 | /* read' and write' are a special read and write, respectively */ | ||
235 | |||
236 | /* read' ISP16_CTRL_PORT and save */ | ||
237 | ctrl = ISP16_IN(ISP16_CTRL_PORT); | ||
238 | |||
239 | /* write' zero to the ctrl port and get response */ | ||
240 | ISP16_OUT(ISP16_CTRL_PORT, 0); | ||
241 | tmp = ISP16_IN(ISP16_CTRL_PORT); | ||
242 | |||
243 | if (tmp != 2) /* isp16 with 82C929 not detected */ | ||
244 | return -1; | ||
245 | |||
246 | /* restore ctrl port value */ | ||
247 | ISP16_OUT(ISP16_CTRL_PORT, ctrl); | ||
248 | |||
249 | return 2; | ||
250 | } | ||
251 | |||
252 | static short __init | ||
253 | isp16_cdi_config(int base, u_char drive_type, int irq, int dma) | ||
254 | { | ||
255 | u_char base_code; | ||
256 | u_char irq_code; | ||
257 | u_char dma_code; | ||
258 | u_char i; | ||
259 | |||
260 | if ((drive_type == ISP16_MITSUMI) && (dma != 0)) | ||
261 | printk("ISP16: Mitsumi cdrom drive has no dma support.\n"); | ||
262 | |||
263 | switch (base) { | ||
264 | case 0x340: | ||
265 | base_code = ISP16_BASE_340; | ||
266 | break; | ||
267 | case 0x330: | ||
268 | base_code = ISP16_BASE_330; | ||
269 | break; | ||
270 | case 0x360: | ||
271 | base_code = ISP16_BASE_360; | ||
272 | break; | ||
273 | case 0x320: | ||
274 | base_code = ISP16_BASE_320; | ||
275 | break; | ||
276 | default: | ||
277 | printk | ||
278 | ("ISP16: base address 0x%03X not supported by cdrom interface.\n", | ||
279 | base); | ||
280 | return -1; | ||
281 | } | ||
282 | switch (irq) { | ||
283 | case 0: | ||
284 | irq_code = ISP16_IRQ_X; | ||
285 | break; /* disable irq */ | ||
286 | case 5: | ||
287 | irq_code = ISP16_IRQ_5; | ||
288 | printk("ISP16: irq 5 shouldn't be used by cdrom interface," | ||
289 | " due to possible conflicts with the sound card.\n"); | ||
290 | break; | ||
291 | case 7: | ||
292 | irq_code = ISP16_IRQ_7; | ||
293 | printk("ISP16: irq 7 shouldn't be used by cdrom interface," | ||
294 | " due to possible conflicts with the sound card.\n"); | ||
295 | break; | ||
296 | case 3: | ||
297 | irq_code = ISP16_IRQ_3; | ||
298 | break; | ||
299 | case 9: | ||
300 | irq_code = ISP16_IRQ_9; | ||
301 | break; | ||
302 | case 10: | ||
303 | irq_code = ISP16_IRQ_10; | ||
304 | break; | ||
305 | case 11: | ||
306 | irq_code = ISP16_IRQ_11; | ||
307 | break; | ||
308 | default: | ||
309 | printk("ISP16: irq %d not supported by cdrom interface.\n", | ||
310 | irq); | ||
311 | return -1; | ||
312 | } | ||
313 | switch (dma) { | ||
314 | case 0: | ||
315 | dma_code = ISP16_DMA_X; | ||
316 | break; /* disable dma */ | ||
317 | case 1: | ||
318 | printk("ISP16: dma 1 cannot be used by cdrom interface," | ||
319 | " due to conflict with the sound card.\n"); | ||
320 | return -1; | ||
321 | break; | ||
322 | case 3: | ||
323 | dma_code = ISP16_DMA_3; | ||
324 | break; | ||
325 | case 5: | ||
326 | dma_code = ISP16_DMA_5; | ||
327 | break; | ||
328 | case 6: | ||
329 | dma_code = ISP16_DMA_6; | ||
330 | break; | ||
331 | case 7: | ||
332 | dma_code = ISP16_DMA_7; | ||
333 | break; | ||
334 | default: | ||
335 | printk("ISP16: dma %d not supported by cdrom interface.\n", | ||
336 | dma); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && | ||
341 | drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && | ||
342 | drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && | ||
343 | drive_type != ISP16_DRIVE_X) { | ||
344 | printk | ||
345 | ("ISP16: drive type (code 0x%02X) not supported by cdrom" | ||
346 | " interface.\n", drive_type); | ||
347 | return -1; | ||
348 | } | ||
349 | |||
350 | /* set type of interface */ | ||
351 | i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ | ||
352 | ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type); | ||
353 | |||
354 | /* enable cdrom on interface with 82C929 chip */ | ||
355 | if (isp16_type > 1) | ||
356 | ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM); | ||
357 | |||
358 | /* set base address, irq and dma */ | ||
359 | i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ | ||
360 | ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static void __exit isp16_exit(void) | ||
366 | { | ||
367 | release_region(ISP16_IO_BASE, ISP16_IO_SIZE); | ||
368 | printk(KERN_INFO "ISP16: module released.\n"); | ||
369 | } | ||
370 | |||
371 | module_init(isp16_init); | ||
372 | module_exit(isp16_exit); | ||
373 | |||
374 | MODULE_LICENSE("GPL"); | ||