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 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 61static short isp16_detect(void); 62static short isp16_c928__detect(void); 63static short isp16_c929__detect(void); 64static short isp16_cdi_config(int base, u_char drive_type, int irq, 65 int dma); 66static short isp16_type; /* dependent on type of interface card */ 67static u_char isp16_ctrl; 68static u_short isp16_enable_port; 69 70static int isp16_cdrom_base = ISP16_CDROM_IO_BASE; 71static int isp16_cdrom_irq = ISP16_CDROM_IRQ; 72static int isp16_cdrom_dma = ISP16_CDROM_DMA; 73static char *isp16_cdrom_type = ISP16_CDROM_TYPE; 74 75module_param(isp16_cdrom_base, int, 0); 76module_param(isp16_cdrom_irq, int, 0); 77module_param(isp16_cdrom_dma, int, 0); 78module_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 85static 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 */ 111static 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 166cleanup_out: 167 release_region(ISP16_IO_BASE, ISP16_IO_SIZE); 168out: 169 return -EIO; 170} 171 172static 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 181static 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 226static 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 252static short __init 253isp16_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 365static 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 371module_init(isp16_init); 372module_exit(isp16_exit); 373 374MODULE_LICENSE("GPL"); 375