PageRenderTime 103ms CodeModel.GetById 17ms app.highlight 72ms RepoModel.GetById 2ms app.codeStats 0ms

/drivers/cdrom/aztcd.c

https://bitbucket.org/evzijst/gittest
C | 2494 lines | 1959 code | 192 blank | 343 comment | 464 complexity | 8208f37e7a0ee868c3fbdee60ba9d725 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1#define AZT_VERSION "2.60"
   2
   3/*      $Id: aztcd.c,v 2.60 1997/11/29 09:51:19 root Exp root $
   4	linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver
   5
   6	Copyright (C) 1994-98 Werner Zimmermann(Werner.Zimmermann@fht-esslingen.de)
   7
   8	based on Mitsumi CDROM driver by  Martin Hariss and preworks by
   9	Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby 
  10	Schirmer.
  11
  12	This program is free software; you can redistribute it and/or modify
  13	it under the terms of the GNU General Public License as published by
  14	the Free Software Foundation; either version 2, or (at your option)
  15	any later version.
  16
  17	This program is distributed in the hope that it will be useful,
  18	but WITHOUT ANY WARRANTY; without even the implied warranty of
  19	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20	GNU General Public License for more details.
  21
  22	You should have received a copy of the GNU General Public License
  23	along with this program; if not, write to the Free Software
  24	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25
  26	HISTORY
  27	V0.0    Adaption to Aztech CD268-01A Version 1.3
  28		Version is PRE_ALPHA, unresolved points:
  29		1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW
  30		   thus driver causes CPU overhead and is very slow 
  31		2. could not find a way to stop the drive, when it is
  32		   in data read mode, therefore I had to set
  33		   msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one
  34		   frame can be read in sequence, this is also the reason for
  35		3. getting 'timeout in state 4' messages, but nevertheless
  36		   it works
  37		W.Zimmermann, Oct. 31, 1994
  38	V0.1    Version is ALPHA, problems #2 and #3 resolved.  
  39		W.Zimmermann, Nov. 3, 1994
  40	V0.2    Modification to some comments, debugging aids for partial test
  41		with Borland C under DOS eliminated. Timer interrupt wait 
  42		STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; 
  43		use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_
  44		SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy 
  45		waiting seems better to me than interrupt rescheduling.
  46		Besides that, when used in the wrong place, STEN_LOW_WAIT causes
  47		kernel panic.
  48		In function aztPlay command ACMD_PLAY_AUDIO added, should make
  49		audio functions work. The Aztech drive needs different commands
  50		to read data tracks and play audio tracks.
  51		W.Zimmermann, Nov. 8, 1994
  52	V0.3    Recognition of missing drive during boot up improved (speeded up).
  53		W.Zimmermann, Nov. 13, 1994
  54	V0.35   Rewrote the control mechanism in azt_poll (formerly mcd_poll) 
  55		including removal of all 'goto' commands. :-); 
  56		J. Nardone, Nov. 14, 1994
  57	V0.4    Renamed variables and constants to 'azt' instead of 'mcd'; had
  58		to make some "compatibility" defines in azt.h; please note,
  59		that the source file was renamed to azt.c, the include file to
  60		azt.h                
  61		Speeded up drive recognition during init (will be a little bit 
  62		slower than before if no drive is installed!); suggested by
  63		Robby Schirmer.
  64		read_count declared volatile and set to AZT_BUF_SIZ to make
  65		drive faster (now 300kB/sec, was 60kB/sec before, measured
  66		by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096';
  67		different AZT_BUF_SIZes were test, above 16 no further im-
  68		provement seems to be possible; suggested by E.Moenkeberg.
  69		W.Zimmermann, Nov. 18, 1994
  70	V0.42   Included getAztStatus command in GetQChannelInfo() to allow
  71		reading Q-channel info on audio disks, if drive is stopped, 
  72		and some other bug fixes in the audio stuff, suggested by 
  73		Robby Schirmer.
  74		Added more ioctls (reading data in mode 1 and mode 2).
  75		Completely removed the old azt_poll() routine.
  76		Detection of ORCHID CDS-3110 in aztcd_init implemented.
  77		Additional debugging aids (see the readme file).
  78		W.Zimmermann, Dec. 9, 1994  
  79	V0.50   Autodetection of drives implemented.
  80		W.Zimmermann, Dec. 12, 1994
  81	V0.52   Prepared for including in the standard kernel, renamed most
  82		variables to contain 'azt', included autoconf.h
  83		W.Zimmermann, Dec. 16, 1994        
  84	V0.6    Version for being included in the standard Linux kernel.
  85		Renamed source and header file to aztcd.c and aztcd.h
  86		W.Zimmermann, Dec. 24, 1994
  87	V0.7    Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case
  88		CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl,
  89		which causes kernel crashes when playing audio, changed 
  90		include-files (config.h instead of autoconf.h, removed
  91		delay.h)
  92		W.Zimmermann, Jan. 8, 1995
  93	V0.72   Some more modifications for adaption to the standard kernel.
  94		W.Zimmermann, Jan. 16, 1995
  95        V0.80   aztcd is now part of the standard kernel since version 1.1.83.
  96                Modified the SET_TIMER and CLEAR_TIMER macros to comply with
  97                the new timer scheme.
  98                W.Zimmermann, Jan. 21, 1995
  99        V0.90   Included CDROMVOLCTRL, but with my Aztech drive I can only turn
 100                the channels on and off. If it works better with your drive, 
 101                please mail me. Also implemented ACMD_CLOSE for CDROMSTART.
 102                W.Zimmermann, Jan. 24, 1995
 103        V1.00   Implemented close and lock tray commands. Patches supplied by
 104		Frank Racis        
 105                Added support for loadable MODULEs, so aztcd can now also be
 106                loaded by insmod and removed by rmmod during run time
 107                Werner Zimmermann, Mar. 24, 95
 108        V1.10   Implemented soundcard configuration for Orchid CDS-3110 drives
 109                connected to Soundwave32 cards. Release for LST 2.1.
 110                (still experimental)
 111                Werner Zimmermann, May 8, 95
 112        V1.20   Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but
 113                sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver-
 114                sion needs an update of Dosemu0.60's cdrom.c, which will come with the 
 115                next revision of Dosemu.
 116                Also Soundwave32 support now works.
 117                Werner Zimmermann, May 22, 95
 118	V1.30   Auto-eject feature. Inspired by Franc Racis (racis@psu.edu)
 119	        Werner Zimmermann, July 4, 95
 120	V1.40   Started multisession support. Implementation copied from mcdx.c
 121	        by Heiko Schlittermann. Not tested yet.
 122	        Werner Zimmermann, July 15, 95
 123        V1.50   Implementation of ioctl CDROMRESET, continued multisession, began
 124                XA, but still untested. Heavy modifications to drive status de-
 125                tection.
 126                Werner Zimmermann, July 25, 95
 127        V1.60   XA support now should work. Speeded up drive recognition in cases, 
 128                where no drive is installed.
 129                Werner Zimmermann, August 8, 1995
 130        V1.70   Multisession support now is completed, but there is still not 
 131                enough testing done. If you can test it, please contact me. For
 132                details please read Documentation/cdrom/aztcd
 133                Werner Zimmermann, August 19, 1995
 134        V1.80   Modification to suit the new kernel boot procedure introduced
 135                with kernel 1.3.33. Will definitely not work with older kernels.
 136                Programming done by Linus himself.
 137                Werner Zimmermann, October 11, 1995
 138	V1.90   Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza.
 139	        Werner Zimmermann, October 21, 1995
 140        V2.00   Changed #include "blk.h" to <linux/blk.h> as the directory
 141                structure was changed. README.aztcd is now /usr/src/docu-
 142                mentation/cdrom/aztcd
 143                Werner Zimmermann, November 10, 95
 144        V2.10   Started to modify azt_poll to prevent reading beyond end of
 145                tracks.
 146                Werner Zimmermann, December 3, 95
 147        V2.20   Changed some comments
 148                Werner Zimmermann, April 1, 96
 149        V2.30   Implemented support for CyCDROM CR520, CR940, Code for CR520 
 150        	delivered by H.Berger with preworks by E.Moenkeberg.
 151                Werner Zimmermann, April 29, 96
 152        V2.40   Reorganized the placement of functions in the source code file
 153                to reflect the layered approach; did not actually change code
 154                Werner Zimmermann, May 1, 96
 155        V2.50   Heiko Eissfeldt suggested to remove some VERIFY_READs in 
 156                aztcd_ioctl; check_aztcd_media_change modified 
 157                Werner Zimmermann, May 16, 96       
 158	V2.60   Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize
 159                Adaption to linux kernel > 2.1.0
 160		Werner Zimmermann, Nov 29, 97
 161		
 162        November 1999 -- Make kernel-parameter implementation work with 2.3.x 
 163	                 Removed init_module & cleanup_module in favor of 
 164			 module_init & module_exit.
 165			 Torben Mathiasen <tmm@image.dk>
 166*/
 167
 168#include <linux/blkdev.h>
 169#include "aztcd.h"
 170
 171#include <linux/module.h>
 172#include <linux/errno.h>
 173#include <linux/sched.h>
 174#include <linux/mm.h>
 175#include <linux/timer.h>
 176#include <linux/fs.h>
 177#include <linux/kernel.h>
 178#include <linux/cdrom.h>
 179#include <linux/ioport.h>
 180#include <linux/string.h>
 181#include <linux/major.h>
 182
 183#include <linux/init.h>
 184
 185#include <asm/system.h>
 186#include <asm/io.h>
 187
 188#include <asm/uaccess.h>
 189
 190/*###########################################################################
 191  Defines
 192  ###########################################################################
 193*/
 194
 195#define MAJOR_NR AZTECH_CDROM_MAJOR
 196#define QUEUE (azt_queue)
 197#define CURRENT elv_next_request(azt_queue)
 198#define SET_TIMER(func, jifs)   delay_timer.expires = jiffies + (jifs); \
 199                                delay_timer.function = (void *) (func); \
 200                                add_timer(&delay_timer);
 201
 202#define CLEAR_TIMER             del_timer(&delay_timer);
 203
 204#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\
 205                                return value;}
 206#define RETURN(message)        {printk("aztcd: Warning: %s failed\n",message);\
 207                                return;}
 208
 209/* Macros to switch the IDE-interface to the slave device and back to the master*/
 210#define SWITCH_IDE_SLAVE  outb_p(0xa0,azt_port+6); \
 211	                  outb_p(0x10,azt_port+6); \
 212	                  outb_p(0x00,azt_port+7); \
 213	                  outb_p(0x10,azt_port+6);
 214#define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6);
 215
 216
 217#if 0
 218#define AZT_TEST
 219#define AZT_TEST1		/* <int-..> */
 220#define AZT_TEST2		/* do_aztcd_request */
 221#define AZT_TEST3		/* AZT_S_state */
 222#define AZT_TEST4		/* QUICK_LOOP-counter */
 223#define AZT_TEST5		/* port(1) state */
 224#define AZT_DEBUG
 225#define AZT_DEBUG_MULTISESSION
 226#endif
 227
 228static struct request_queue *azt_queue;
 229
 230static int current_valid(void)
 231{
 232        return CURRENT &&
 233		CURRENT->cmd == READ &&
 234		CURRENT->sector != -1;
 235}
 236
 237#define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
 238#define AZT_BUF_SIZ 16
 239
 240#define READ_TIMEOUT 3000
 241
 242#define azt_port aztcd		/*needed for the modutils */
 243
 244/*##########################################################################
 245  Type Definitions
 246  ##########################################################################
 247*/
 248enum azt_state_e { AZT_S_IDLE,	/* 0 */
 249	AZT_S_START,		/* 1 */
 250	AZT_S_MODE,		/* 2 */
 251	AZT_S_READ,		/* 3 */
 252	AZT_S_DATA,		/* 4 */
 253	AZT_S_STOP,		/* 5 */
 254	AZT_S_STOPPING		/* 6 */
 255};
 256enum azt_read_modes { AZT_MODE_0,	/*read mode for audio disks, not supported by Aztech firmware */
 257	AZT_MODE_1,		/*read mode for normal CD-ROMs */
 258	AZT_MODE_2		/*read mode for XA CD-ROMs */
 259};
 260
 261/*##########################################################################
 262  Global Variables
 263  ##########################################################################
 264*/
 265static int aztPresent = 0;
 266
 267static volatile int azt_transfer_is_active = 0;
 268
 269static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ];	/*buffer for block size conversion */
 270#if AZT_PRIVATE_IOCTLS
 271static char buf[CD_FRAMESIZE_RAW];	/*separate buffer for the ioctls */
 272#endif
 273
 274static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
 275static volatile int azt_buf_in, azt_buf_out = -1;
 276static volatile int azt_error = 0;
 277static int azt_open_count = 0;
 278static volatile enum azt_state_e azt_state = AZT_S_IDLE;
 279#ifdef AZT_TEST3
 280static volatile enum azt_state_e azt_state_old = AZT_S_STOP;
 281static volatile int azt_st_old = 0;
 282#endif
 283static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
 284
 285static int azt_mode = -1;
 286static volatile int azt_read_count = 1;
 287
 288static int azt_port = AZT_BASE_ADDR;
 289
 290module_param(azt_port, int, 0);
 291
 292static int azt_port_auto[16] = AZT_BASE_AUTO;
 293
 294static char azt_cont = 0;
 295static char azt_init_end = 0;
 296static char azt_auto_eject = AZT_AUTO_EJECT;
 297
 298static int AztTimeout, AztTries;
 299static DECLARE_WAIT_QUEUE_HEAD(azt_waitq);
 300static struct timer_list delay_timer = TIMER_INITIALIZER(NULL, 0, 0);
 301
 302static struct azt_DiskInfo DiskInfo;
 303static struct azt_Toc Toc[MAX_TRACKS];
 304static struct azt_Play_msf azt_Play;
 305
 306static int aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 307static char aztDiskChanged = 1;
 308static char aztTocUpToDate = 0;
 309
 310static unsigned char aztIndatum;
 311static unsigned long aztTimeOutCount;
 312static int aztCmd = 0;
 313
 314static DEFINE_SPINLOCK(aztSpin);
 315
 316/*###########################################################################
 317   Function Prototypes
 318  ###########################################################################
 319*/
 320/* CDROM Drive Low Level I/O Functions */
 321static void aztStatTimer(void);
 322
 323/* CDROM Drive Command Functions */
 324static int aztGetDiskInfo(void);
 325#if AZT_MULTISESSION
 326static int aztGetMultiDiskInfo(void);
 327#endif
 328static int aztGetToc(int multi);
 329
 330/* Kernel Interface Functions */
 331static int check_aztcd_media_change(struct gendisk *disk);
 332static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
 333		       unsigned long arg);
 334static int aztcd_open(struct inode *ip, struct file *fp);
 335static int aztcd_release(struct inode *inode, struct file *file);
 336
 337static struct block_device_operations azt_fops = {
 338	.owner		= THIS_MODULE,
 339	.open		= aztcd_open,
 340	.release	= aztcd_release,
 341	.ioctl		= aztcd_ioctl,
 342	.media_changed	= check_aztcd_media_change,
 343};
 344
 345/* Aztcd State Machine: Controls Drive Operating State */
 346static void azt_poll(void);
 347
 348/* Miscellaneous support functions */
 349static void azt_hsg2msf(long hsg, struct msf *msf);
 350static long azt_msf2hsg(struct msf *mp);
 351static void azt_bin2bcd(unsigned char *p);
 352static int azt_bcd2bin(unsigned char bcd);
 353
 354/*##########################################################################
 355  CDROM Drive Low Level I/O Functions
 356  ##########################################################################
 357*/
 358/* Macros for the drive hardware interface handshake, these macros use
 359   busy waiting */
 360/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
 361# define OP_OK op_ok()
 362static void op_ok(void)
 363{
 364	aztTimeOutCount = 0;
 365	do {
 366		aztIndatum = inb(DATA_PORT);
 367		aztTimeOutCount++;
 368		if (aztTimeOutCount >= AZT_TIMEOUT) {
 369			printk("aztcd: Error Wait OP_OK\n");
 370			break;
 371		}
 372	} while (aztIndatum != AFL_OP_OK);
 373}
 374
 375/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
 376#if 0
 377# define PA_OK pa_ok()
 378static void pa_ok(void)
 379{
 380	aztTimeOutCount = 0;
 381	do {
 382		aztIndatum = inb(DATA_PORT);
 383		aztTimeOutCount++;
 384		if (aztTimeOutCount >= AZT_TIMEOUT) {
 385			printk("aztcd: Error Wait PA_OK\n");
 386			break;
 387		}
 388	} while (aztIndatum != AFL_PA_OK);
 389}
 390#endif
 391
 392/* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/
 393# define STEN_LOW  sten_low()
 394static void sten_low(void)
 395{
 396	aztTimeOutCount = 0;
 397	do {
 398		aztIndatum = inb(STATUS_PORT);
 399		aztTimeOutCount++;
 400		if (aztTimeOutCount >= AZT_TIMEOUT) {
 401			if (azt_init_end)
 402				printk
 403				    ("aztcd: Error Wait STEN_LOW commands:%x\n",
 404				     aztCmd);
 405			break;
 406		}
 407	} while (aztIndatum & AFL_STATUS);
 408}
 409
 410/* Wait for DTEN=Low = handshake signal 'Data available'*/
 411# define DTEN_LOW dten_low()
 412static void dten_low(void)
 413{
 414	aztTimeOutCount = 0;
 415	do {
 416		aztIndatum = inb(STATUS_PORT);
 417		aztTimeOutCount++;
 418		if (aztTimeOutCount >= AZT_TIMEOUT) {
 419			printk("aztcd: Error Wait DTEN_OK\n");
 420			break;
 421		}
 422	} while (aztIndatum & AFL_DATA);
 423}
 424
 425/* 
 426 * Macro for timer wait on STEN=Low, should only be used for 'slow' commands;
 427 * may cause kernel panic when used in the wrong place
 428*/
 429#define STEN_LOW_WAIT   statusAzt()
 430static void statusAzt(void)
 431{
 432	AztTimeout = AZT_STATUS_DELAY;
 433	SET_TIMER(aztStatTimer, HZ / 100);
 434	sleep_on(&azt_waitq);
 435	if (AztTimeout <= 0)
 436		printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",
 437		       aztCmd);
 438	return;
 439}
 440
 441static void aztStatTimer(void)
 442{
 443	if (!(inb(STATUS_PORT) & AFL_STATUS)) {
 444		wake_up(&azt_waitq);
 445		return;
 446	}
 447	AztTimeout--;
 448	if (AztTimeout <= 0) {
 449		wake_up(&azt_waitq);
 450		printk("aztcd: Error aztStatTimer: Timeout\n");
 451		return;
 452	}
 453	SET_TIMER(aztStatTimer, HZ / 100);
 454}
 455
 456/*##########################################################################
 457  CDROM Drive Command Functions
 458  ##########################################################################
 459*/
 460/* 
 461 * Send a single command, return -1 on error, else 0
 462*/
 463static int aztSendCmd(int cmd)
 464{
 465	unsigned char data;
 466	int retry;
 467
 468#ifdef AZT_DEBUG
 469	printk("aztcd: Executing command %x\n", cmd);
 470#endif
 471
 472	if ((azt_port == 0x1f0) || (azt_port == 0x170))
 473		SWITCH_IDE_SLAVE;	/*switch IDE interface to slave configuration */
 474
 475	aztCmd = cmd;
 476	outb(POLLED, MODE_PORT);
 477	do {
 478		if (inb(STATUS_PORT) & AFL_STATUS)
 479			break;
 480		inb(DATA_PORT);	/* if status left from last command, read and */
 481	} while (1);		/* discard it */
 482	do {
 483		if (inb(STATUS_PORT) & AFL_DATA)
 484			break;
 485		inb(DATA_PORT);	/* if data left from last command, read and */
 486	} while (1);		/* discard it */
 487	for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
 488		outb((unsigned char) cmd, CMD_PORT);
 489		STEN_LOW;
 490		data = inb(DATA_PORT);
 491		if (data == AFL_OP_OK) {
 492			return 0;
 493		}		/*OP_OK? */
 494		if (data == AFL_OP_ERR) {
 495			STEN_LOW;
 496			data = inb(DATA_PORT);
 497			printk
 498			    ("### Error 1 aztcd: aztSendCmd %x  Error Code %x\n",
 499			     cmd, data);
 500		}
 501	}
 502	if (retry >= AZT_RETRY_ATTEMPTS) {
 503		printk("### Error 2 aztcd: aztSendCmd %x \n", cmd);
 504		azt_error = 0xA5;
 505	}
 506	RETURNM("aztSendCmd", -1);
 507}
 508
 509/*
 510 * Send a play or read command to the drive, return -1 on error, else 0
 511*/
 512static int sendAztCmd(int cmd, struct azt_Play_msf *params)
 513{
 514	unsigned char data;
 515	int retry;
 516
 517#ifdef AZT_DEBUG
 518	printk("aztcd: play start=%02x:%02x:%02x  end=%02x:%02x:%02x\n",
 519	       params->start.min, params->start.sec, params->start.frame,
 520	       params->end.min, params->end.sec, params->end.frame);
 521#endif
 522	for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
 523		aztSendCmd(cmd);
 524		outb(params->start.min, CMD_PORT);
 525		outb(params->start.sec, CMD_PORT);
 526		outb(params->start.frame, CMD_PORT);
 527		outb(params->end.min, CMD_PORT);
 528		outb(params->end.sec, CMD_PORT);
 529		outb(params->end.frame, CMD_PORT);
 530		STEN_LOW;
 531		data = inb(DATA_PORT);
 532		if (data == AFL_PA_OK) {
 533			return 0;
 534		}		/*PA_OK ? */
 535		if (data == AFL_PA_ERR) {
 536			STEN_LOW;
 537			data = inb(DATA_PORT);
 538			printk
 539			    ("### Error 1 aztcd: sendAztCmd %x  Error Code %x\n",
 540			     cmd, data);
 541		}
 542	}
 543	if (retry >= AZT_RETRY_ATTEMPTS) {
 544		printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd);
 545		azt_error = 0xA5;
 546	}
 547	RETURNM("sendAztCmd", -1);
 548}
 549
 550/*
 551 * Send a seek command to the drive, return -1 on error, else 0
 552*/
 553static int aztSeek(struct azt_Play_msf *params)
 554{
 555	unsigned char data;
 556	int retry;
 557
 558#ifdef AZT_DEBUG
 559	printk("aztcd: aztSeek %02x:%02x:%02x\n",
 560	       params->start.min, params->start.sec, params->start.frame);
 561#endif
 562	for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
 563		aztSendCmd(ACMD_SEEK);
 564		outb(params->start.min, CMD_PORT);
 565		outb(params->start.sec, CMD_PORT);
 566		outb(params->start.frame, CMD_PORT);
 567		STEN_LOW;
 568		data = inb(DATA_PORT);
 569		if (data == AFL_PA_OK) {
 570			return 0;
 571		}		/*PA_OK ? */
 572		if (data == AFL_PA_ERR) {
 573			STEN_LOW;
 574			data = inb(DATA_PORT);
 575			printk("### Error 1 aztcd: aztSeek\n");
 576		}
 577	}
 578	if (retry >= AZT_RETRY_ATTEMPTS) {
 579		printk("### Error 2 aztcd: aztSeek\n ");
 580		azt_error = 0xA5;
 581	}
 582	RETURNM("aztSeek", -1);
 583}
 584
 585/* Send a Set Disk Type command
 586   does not seem to work with Aztech drives, behavior is completely indepen-
 587   dent on which mode is set ???
 588*/
 589static int aztSetDiskType(int type)
 590{
 591	unsigned char data;
 592	int retry;
 593
 594#ifdef AZT_DEBUG
 595	printk("aztcd: set disk type command: type= %i\n", type);
 596#endif
 597	for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
 598		aztSendCmd(ACMD_SET_DISK_TYPE);
 599		outb(type, CMD_PORT);
 600		STEN_LOW;
 601		data = inb(DATA_PORT);
 602		if (data == AFL_PA_OK) {	/*PA_OK ? */
 603			azt_read_mode = type;
 604			return 0;
 605		}
 606		if (data == AFL_PA_ERR) {
 607			STEN_LOW;
 608			data = inb(DATA_PORT);
 609			printk
 610			    ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",
 611			     type, data);
 612		}
 613	}
 614	if (retry >= AZT_RETRY_ATTEMPTS) {
 615		printk("### Error 2 aztcd: aztSetDiskType %x\n ", type);
 616		azt_error = 0xA5;
 617	}
 618	RETURNM("aztSetDiskType", -1);
 619}
 620
 621
 622/* used in azt_poll to poll the status, expects another program to issue a 
 623 * ACMD_GET_STATUS directly before 
 624 */
 625static int aztStatus(void)
 626{
 627	int st;
 628/*	int i;
 629
 630	i = inb(STATUS_PORT) & AFL_STATUS;    is STEN=0?    ???
 631	if (!i)
 632*/ STEN_LOW;
 633	if (aztTimeOutCount < AZT_TIMEOUT) {
 634		st = inb(DATA_PORT) & 0xFF;
 635		return st;
 636	} else
 637		RETURNM("aztStatus", -1);
 638}
 639
 640/*
 641 * Get the drive status
 642 */
 643static int getAztStatus(void)
 644{
 645	int st;
 646
 647	if (aztSendCmd(ACMD_GET_STATUS))
 648		RETURNM("getAztStatus 1", -1);
 649	STEN_LOW;
 650	st = inb(DATA_PORT) & 0xFF;
 651#ifdef AZT_DEBUG
 652	printk("aztcd: Status = %x\n", st);
 653#endif
 654	if ((st == 0xFF) || (st & AST_CMD_CHECK)) {
 655		printk
 656		    ("aztcd: AST_CMD_CHECK error or no status available\n");
 657		return -1;
 658	}
 659
 660	if (((st & AST_MODE_BITS) != AST_BUSY)
 661	    && (aztAudioStatus == CDROM_AUDIO_PLAY))
 662		/* XXX might be an error? look at q-channel? */
 663		aztAudioStatus = CDROM_AUDIO_COMPLETED;
 664
 665	if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) {
 666		aztDiskChanged = 1;
 667		aztTocUpToDate = 0;
 668		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 669	}
 670	return st;
 671}
 672
 673
 674/*
 675 * Send a 'Play' command and get the status.  Use only from the top half.
 676 */
 677static int aztPlay(struct azt_Play_msf *arg)
 678{
 679	if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0)
 680		RETURNM("aztPlay", -1);
 681	return 0;
 682}
 683
 684/*
 685 * Subroutines to automatically close the door (tray) and 
 686 * lock it closed when the cd is mounted.  Leave the tray
 687 * locking as an option
 688 */
 689static void aztCloseDoor(void)
 690{
 691	aztSendCmd(ACMD_CLOSE);
 692	STEN_LOW;
 693	return;
 694}
 695
 696static void aztLockDoor(void)
 697{
 698#if AZT_ALLOW_TRAY_LOCK
 699	aztSendCmd(ACMD_LOCK);
 700	STEN_LOW;
 701#endif
 702	return;
 703}
 704
 705static void aztUnlockDoor(void)
 706{
 707#if AZT_ALLOW_TRAY_LOCK
 708	aztSendCmd(ACMD_UNLOCK);
 709	STEN_LOW;
 710#endif
 711	return;
 712}
 713
 714/*
 715 * Read a value from the drive.  Should return quickly, so a busy wait
 716 * is used to avoid excessive rescheduling. The read command itself must
 717 * be issued with aztSendCmd() directly before
 718 */
 719static int aztGetValue(unsigned char *result)
 720{
 721	int s;
 722
 723	STEN_LOW;
 724	if (aztTimeOutCount >= AZT_TIMEOUT) {
 725		printk("aztcd: aztGetValue timeout\n");
 726		return -1;
 727	}
 728	s = inb(DATA_PORT) & 0xFF;
 729	*result = (unsigned char) s;
 730	return 0;
 731}
 732
 733/*
 734 * Read the current Q-channel info.  Also used for reading the
 735 * table of contents.
 736 */
 737static int aztGetQChannelInfo(struct azt_Toc *qp)
 738{
 739	unsigned char notUsed;
 740	int st;
 741
 742#ifdef AZT_DEBUG
 743	printk("aztcd: starting aztGetQChannelInfo  Time:%li\n", jiffies);
 744#endif
 745	if ((st = getAztStatus()) == -1)
 746		RETURNM("aztGetQChannelInfo 1", -1);
 747	if (aztSendCmd(ACMD_GET_Q_CHANNEL))
 748		RETURNM("aztGetQChannelInfo 2", -1);
 749	/*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */
 750	if (aztGetValue(&notUsed))
 751		RETURNM("aztGetQChannelInfo 3", -1);	/*??? Nullbyte einlesen */
 752	if ((st & AST_MODE_BITS) == AST_INITIAL) {
 753		qp->ctrl_addr = 0;	/* when audio stop ACMD_GET_Q_CHANNEL returns */
 754		qp->track = 0;	/* only one byte with Aztech drives */
 755		qp->pointIndex = 0;
 756		qp->trackTime.min = 0;
 757		qp->trackTime.sec = 0;
 758		qp->trackTime.frame = 0;
 759		qp->diskTime.min = 0;
 760		qp->diskTime.sec = 0;
 761		qp->diskTime.frame = 0;
 762		return 0;
 763	} else {
 764		if (aztGetValue(&qp->ctrl_addr) < 0)
 765			RETURNM("aztGetQChannelInfo 4", -1);
 766		if (aztGetValue(&qp->track) < 0)
 767			RETURNM("aztGetQChannelInfo 4", -1);
 768		if (aztGetValue(&qp->pointIndex) < 0)
 769			RETURNM("aztGetQChannelInfo 4", -1);
 770		if (aztGetValue(&qp->trackTime.min) < 0)
 771			RETURNM("aztGetQChannelInfo 4", -1);
 772		if (aztGetValue(&qp->trackTime.sec) < 0)
 773			RETURNM("aztGetQChannelInfo 4", -1);
 774		if (aztGetValue(&qp->trackTime.frame) < 0)
 775			RETURNM("aztGetQChannelInfo 4", -1);
 776		if (aztGetValue(&notUsed) < 0)
 777			RETURNM("aztGetQChannelInfo 4", -1);
 778		if (aztGetValue(&qp->diskTime.min) < 0)
 779			RETURNM("aztGetQChannelInfo 4", -1);
 780		if (aztGetValue(&qp->diskTime.sec) < 0)
 781			RETURNM("aztGetQChannelInfo 4", -1);
 782		if (aztGetValue(&qp->diskTime.frame) < 0)
 783			RETURNM("aztGetQChannelInfo 4", -1);
 784	}
 785#ifdef AZT_DEBUG
 786	printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n", jiffies);
 787#endif
 788	return 0;
 789}
 790
 791/*
 792 * Read the table of contents (TOC) and TOC header if necessary
 793 */
 794static int aztUpdateToc(void)
 795{
 796	int st;
 797
 798#ifdef AZT_DEBUG
 799	printk("aztcd: starting aztUpdateToc  Time:%li\n", jiffies);
 800#endif
 801	if (aztTocUpToDate)
 802		return 0;
 803
 804	if (aztGetDiskInfo() < 0)
 805		return -EIO;
 806
 807	if (aztGetToc(0) < 0)
 808		return -EIO;
 809
 810	/*audio disk detection
 811	   with my Aztech drive there is no audio status bit, so I use the copy
 812	   protection bit of the first track. If this track is copy protected 
 813	   (copy bit = 0), I assume, it's an audio  disk. Strange, but works ??? */
 814	if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
 815		DiskInfo.audio = 1;
 816	else
 817		DiskInfo.audio = 0;
 818
 819	/* XA detection */
 820	if (!DiskInfo.audio) {
 821		azt_Play.start.min = 0;	/*XA detection only seems to work */
 822		azt_Play.start.sec = 2;	/*when we play a track */
 823		azt_Play.start.frame = 0;
 824		azt_Play.end.min = 0;
 825		azt_Play.end.sec = 0;
 826		azt_Play.end.frame = 1;
 827		if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
 828			return -1;
 829		DTEN_LOW;
 830		for (st = 0; st < CD_FRAMESIZE; st++)
 831			inb(DATA_PORT);
 832	}
 833	DiskInfo.xa = getAztStatus() & AST_MODE;
 834	if (DiskInfo.xa) {
 835		printk
 836		    ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
 837	}
 838
 839	/*multisession detection
 840	   support for multisession CDs is done automatically with Aztech drives,
 841	   we don't have to take care about TOC redirection; if we want the isofs
 842	   to take care about redirection, we have to set AZT_MULTISESSION to 1 */
 843	DiskInfo.multi = 0;
 844#if AZT_MULTISESSION
 845	if (DiskInfo.xa) {
 846		aztGetMultiDiskInfo();	/*here Disk.Info.multi is set */
 847	}
 848#endif
 849	if (DiskInfo.multi) {
 850		DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
 851		DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
 852		DiskInfo.lastSession.frame =
 853		    Toc[DiskInfo.next].diskTime.frame;
 854		printk("aztcd: Multisession support experimental\n");
 855	} else {
 856		DiskInfo.lastSession.min =
 857		    Toc[DiskInfo.first].diskTime.min;
 858		DiskInfo.lastSession.sec =
 859		    Toc[DiskInfo.first].diskTime.sec;
 860		DiskInfo.lastSession.frame =
 861		    Toc[DiskInfo.first].diskTime.frame;
 862	}
 863
 864	aztTocUpToDate = 1;
 865#ifdef AZT_DEBUG
 866	printk("aztcd: exiting aztUpdateToc  Time:%li\n", jiffies);
 867#endif
 868	return 0;
 869}
 870
 871
 872/* Read the table of contents header, i.e. no. of tracks and start of first 
 873 * track
 874 */
 875static int aztGetDiskInfo(void)
 876{
 877	int limit;
 878	unsigned char test;
 879	struct azt_Toc qInfo;
 880
 881#ifdef AZT_DEBUG
 882	printk("aztcd: starting aztGetDiskInfo  Time:%li\n", jiffies);
 883#endif
 884	if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
 885		RETURNM("aztGetDiskInfo 1", -1);
 886	STEN_LOW_WAIT;
 887	test = 0;
 888	for (limit = 300; limit > 0; limit--) {
 889		if (aztGetQChannelInfo(&qInfo) < 0)
 890			RETURNM("aztGetDiskInfo 2", -1);
 891		if (qInfo.pointIndex == 0xA0) {	/*Number of FirstTrack */
 892			DiskInfo.first = qInfo.diskTime.min;
 893			DiskInfo.first = azt_bcd2bin(DiskInfo.first);
 894			test = test | 0x01;
 895		}
 896		if (qInfo.pointIndex == 0xA1) {	/*Number of LastTrack */
 897			DiskInfo.last = qInfo.diskTime.min;
 898			DiskInfo.last = azt_bcd2bin(DiskInfo.last);
 899			test = test | 0x02;
 900		}
 901		if (qInfo.pointIndex == 0xA2) {	/*DiskLength */
 902			DiskInfo.diskLength.min = qInfo.diskTime.min;
 903			DiskInfo.diskLength.sec = qInfo.diskTime.sec;
 904			DiskInfo.diskLength.frame = qInfo.diskTime.frame;
 905			test = test | 0x04;
 906		}
 907		if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) {	/*StartTime of First Track */
 908			DiskInfo.firstTrack.min = qInfo.diskTime.min;
 909			DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
 910			DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
 911			test = test | 0x08;
 912		}
 913		if (test == 0x0F)
 914			break;
 915	}
 916#ifdef AZT_DEBUG
 917	printk("aztcd: exiting aztGetDiskInfo  Time:%li\n", jiffies);
 918	printk
 919	    ("Disk Info: first %d last %d length %02X:%02X.%02X dez  first %02X:%02X.%02X dez\n",
 920	     DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
 921	     DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
 922	     DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
 923	     DiskInfo.firstTrack.frame);
 924#endif
 925	if (test != 0x0F)
 926		return -1;
 927	return 0;
 928}
 929
 930#if AZT_MULTISESSION
 931/*
 932 * Get Multisession Disk Info
 933 */
 934static int aztGetMultiDiskInfo(void)
 935{
 936	int limit, k = 5;
 937	unsigned char test;
 938	struct azt_Toc qInfo;
 939
 940#ifdef AZT_DEBUG
 941	printk("aztcd: starting aztGetMultiDiskInfo\n");
 942#endif
 943
 944	do {
 945		azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min;
 946		azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec;
 947		azt_Play.start.frame =
 948		    Toc[DiskInfo.last + 1].diskTime.frame;
 949		test = 0;
 950
 951		for (limit = 30; limit > 0; limit--) {	/*Seek for LeadIn of next session */
 952			if (aztSeek(&azt_Play))
 953				RETURNM("aztGetMultiDiskInfo 1", -1);
 954			if (aztGetQChannelInfo(&qInfo) < 0)
 955				RETURNM("aztGetMultiDiskInfo 2", -1);
 956			if ((qInfo.track == 0) && (qInfo.pointIndex))
 957				break;	/*LeadIn found */
 958			if ((azt_Play.start.sec += 10) > 59) {
 959				azt_Play.start.sec = 0;
 960				azt_Play.start.min++;
 961			}
 962		}
 963		if (!limit)
 964			break;	/*Check, if a leadin track was found, if not we're
 965				   at the end of the disk */
 966#ifdef AZT_DEBUG_MULTISESSION
 967		printk("leadin found track %d  pointIndex %x  limit %d\n",
 968		       qInfo.track, qInfo.pointIndex, limit);
 969#endif
 970		for (limit = 300; limit > 0; limit--) {
 971			if (++azt_Play.start.frame > 74) {
 972				azt_Play.start.frame = 0;
 973				if (azt_Play.start.sec > 59) {
 974					azt_Play.start.sec = 0;
 975					azt_Play.start.min++;
 976				}
 977			}
 978			if (aztSeek(&azt_Play))
 979				RETURNM("aztGetMultiDiskInfo 3", -1);
 980			if (aztGetQChannelInfo(&qInfo) < 0)
 981				RETURNM("aztGetMultiDiskInfo 4", -1);
 982			if (qInfo.pointIndex == 0xA0) {	/*Number of NextTrack */
 983				DiskInfo.next = qInfo.diskTime.min;
 984				DiskInfo.next = azt_bcd2bin(DiskInfo.next);
 985				test = test | 0x01;
 986			}
 987			if (qInfo.pointIndex == 0xA1) {	/*Number of LastTrack */
 988				DiskInfo.last = qInfo.diskTime.min;
 989				DiskInfo.last = azt_bcd2bin(DiskInfo.last);
 990				test = test | 0x02;
 991			}
 992			if (qInfo.pointIndex == 0xA2) {	/*DiskLength */
 993				DiskInfo.diskLength.min =
 994				    qInfo.diskTime.min;
 995				DiskInfo.diskLength.sec =
 996				    qInfo.diskTime.sec;
 997				DiskInfo.diskLength.frame =
 998				    qInfo.diskTime.frame;
 999				test = test | 0x04;
1000			}
1001			if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) {	/*StartTime of Next Track */
1002				DiskInfo.nextSession.min =
1003				    qInfo.diskTime.min;
1004				DiskInfo.nextSession.sec =
1005				    qInfo.diskTime.sec;
1006				DiskInfo.nextSession.frame =
1007				    qInfo.diskTime.frame;
1008				test = test | 0x08;
1009			}
1010			if (test == 0x0F)
1011				break;
1012		}
1013#ifdef AZT_DEBUG_MULTISESSION
1014		printk
1015		    ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez  first %02x:%02x.%02x dez  next %02x:%02x.%02x dez\n",
1016		     DiskInfo.first, DiskInfo.next, DiskInfo.last,
1017		     DiskInfo.diskLength.min, DiskInfo.diskLength.sec,
1018		     DiskInfo.diskLength.frame, DiskInfo.firstTrack.min,
1019		     DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame,
1020		     DiskInfo.nextSession.min, DiskInfo.nextSession.sec,
1021		     DiskInfo.nextSession.frame);
1022#endif
1023		if (test != 0x0F)
1024			break;
1025		else
1026			DiskInfo.multi = 1;	/*found TOC of more than one session */
1027		aztGetToc(1);
1028	} while (--k);
1029
1030#ifdef AZT_DEBUG
1031	printk("aztcd: exiting aztGetMultiDiskInfo  Time:%li\n", jiffies);
1032#endif
1033	return 0;
1034}
1035#endif
1036
1037/*
1038 * Read the table of contents (TOC)
1039 */
1040static int aztGetToc(int multi)
1041{
1042	int i, px;
1043	int limit;
1044	struct azt_Toc qInfo;
1045
1046#ifdef AZT_DEBUG
1047	printk("aztcd: starting aztGetToc  Time:%li\n", jiffies);
1048#endif
1049	if (!multi) {
1050		for (i = 0; i < MAX_TRACKS; i++)
1051			Toc[i].pointIndex = 0;
1052		i = DiskInfo.last + 3;
1053	} else {
1054		for (i = DiskInfo.next; i < MAX_TRACKS; i++)
1055			Toc[i].pointIndex = 0;
1056		i = DiskInfo.last + 4 - DiskInfo.next;
1057	}
1058
1059/*Is there a good reason to stop motor before TOC read?
1060  if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
1061      STEN_LOW_WAIT;
1062*/
1063
1064	if (!multi) {
1065		azt_mode = 0x05;
1066		if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
1067			RETURNM("aztGetToc 2", -1);
1068		STEN_LOW_WAIT;
1069	}
1070	for (limit = 300; limit > 0; limit--) {
1071		if (multi) {
1072			if (++azt_Play.start.sec > 59) {
1073				azt_Play.start.sec = 0;
1074				azt_Play.start.min++;
1075			}
1076			if (aztSeek(&azt_Play))
1077				RETURNM("aztGetToc 3", -1);
1078		}
1079		if (aztGetQChannelInfo(&qInfo) < 0)
1080			break;
1081
1082		px = azt_bcd2bin(qInfo.pointIndex);
1083
1084		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1085			if (Toc[px].pointIndex == 0) {
1086				Toc[px] = qInfo;
1087				i--;
1088			}
1089
1090		if (i <= 0)
1091			break;
1092	}
1093
1094	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1095	Toc[DiskInfo.last].trackTime = DiskInfo.diskLength;
1096
1097#ifdef AZT_DEBUG_MULTISESSION
1098	printk("aztcd: exiting aztGetToc\n");
1099	for (i = 1; i <= DiskInfo.last + 1; i++)
1100		printk
1101		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
1102		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1103		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
1104		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
1105		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1106	for (i = 100; i < 103; i++)
1107		printk
1108		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
1109		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1110		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
1111		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
1112		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1113#endif
1114
1115	return limit > 0 ? 0 : -1;
1116}
1117
1118
1119/*##########################################################################
1120  Kernel Interface Functions
1121  ##########################################################################
1122*/
1123
1124#ifndef MODULE
1125static int __init aztcd_setup(char *str)
1126{
1127	int ints[4];
1128
1129	(void) get_options(str, ARRAY_SIZE(ints), ints);
1130
1131	if (ints[0] > 0)
1132		azt_port = ints[1];
1133	if (ints[1] > 1)
1134		azt_cont = ints[2];
1135	return 1;
1136}
1137
1138__setup("aztcd=", aztcd_setup);
1139
1140#endif				/* !MODULE */
1141
1142/* 
1143 * Checking if the media has been changed
1144*/
1145static int check_aztcd_media_change(struct gendisk *disk)
1146{
1147	if (aztDiskChanged) {	/* disk changed */
1148		aztDiskChanged = 0;
1149		return 1;
1150	} else
1151		return 0;	/* no change */
1152}
1153
1154/*
1155 * Kernel IO-controls
1156*/
1157static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
1158		       unsigned long arg)
1159{
1160	int i;
1161	struct azt_Toc qInfo;
1162	struct cdrom_ti ti;
1163	struct cdrom_tochdr tocHdr;
1164	struct cdrom_msf msf;
1165	struct cdrom_tocentry entry;
1166	struct azt_Toc *tocPtr;
1167	struct cdrom_subchnl subchnl;
1168	struct cdrom_volctrl volctrl;
1169	void __user *argp = (void __user *)arg;
1170
1171#ifdef AZT_DEBUG
1172	printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",
1173	       cmd, jiffies);
1174	printk("aztcd Status %x\n", getAztStatus());
1175#endif
1176	if (!ip)
1177		RETURNM("aztcd_ioctl 1", -EINVAL);
1178	if (getAztStatus() < 0)
1179		RETURNM("aztcd_ioctl 2", -EIO);
1180	if ((!aztTocUpToDate) || (aztDiskChanged)) {
1181		if ((i = aztUpdateToc()) < 0)
1182			RETURNM("aztcd_ioctl 3", i);	/* error reading TOC */
1183	}
1184
1185	switch (cmd) {
1186	case CDROMSTART:	/* Spin up the drive. Don't know, what to do,
1187				   at least close the tray */
1188#if AZT_PRIVATE_IOCTLS
1189		if (aztSendCmd(ACMD_CLOSE))
1190			RETURNM("aztcd_ioctl 4", -1);
1191		STEN_LOW_WAIT;
1192#endif
1193		break;
1194	case CDROMSTOP:	/* Spin down the drive */
1195		if (aztSendCmd(ACMD_STOP))
1196			RETURNM("aztcd_ioctl 5", -1);
1197		STEN_LOW_WAIT;
1198		/* should we do anything if it fails? */
1199		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1200		break;
1201	case CDROMPAUSE:	/* Pause the drive */
1202		if (aztAudioStatus != CDROM_AUDIO_PLAY)
1203			return -EINVAL;
1204
1205		if (aztGetQChannelInfo(&qInfo) < 0) {	/* didn't get q channel info */
1206			aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1207			RETURNM("aztcd_ioctl 7", 0);
1208		}
1209		azt_Play.start = qInfo.diskTime;	/* remember restart point */
1210
1211		if (aztSendCmd(ACMD_PAUSE))
1212			RETURNM("aztcd_ioctl 8", -1);
1213		STEN_LOW_WAIT;
1214		aztAudioStatus = CDROM_AUDIO_PAUSED;
1215		break;
1216	case CDROMRESUME:	/* Play it again, Sam */
1217		if (aztAudioStatus != CDROM_AUDIO_PAUSED)
1218			return -EINVAL;
1219		/* restart the drive at the saved position. */
1220		i = aztPlay(&azt_Play);
1221		if (i < 0) {
1222			aztAudioStatus = CDROM_AUDIO_ERROR;
1223			return -EIO;
1224		}
1225		aztAudioStatus = CDROM_AUDIO_PLAY;
1226		break;
1227	case CDROMMULTISESSION:	/*multisession support -- experimental */
1228		{
1229			struct cdrom_multisession ms;
1230#ifdef AZT_DEBUG
1231			printk("aztcd ioctl MULTISESSION\n");
1232#endif
1233			if (copy_from_user(&ms, argp,
1234			     sizeof(struct cdrom_multisession)))
1235				return -EFAULT;
1236			if (ms.addr_format == CDROM_MSF) {
1237				ms.addr.msf.minute =
1238				    azt_bcd2bin(DiskInfo.lastSession.min);
1239				ms.addr.msf.second =
1240				    azt_bcd2bin(DiskInfo.lastSession.sec);
1241				ms.addr.msf.frame =
1242				    azt_bcd2bin(DiskInfo.lastSession.
1243						frame);
1244			} else if (ms.addr_format == CDROM_LBA)
1245				ms.addr.lba =
1246				    azt_msf2hsg(&DiskInfo.lastSession);
1247			else
1248				return -EINVAL;
1249			ms.xa_flag = DiskInfo.xa;
1250			if (copy_to_user(argp, &ms,
1251			     sizeof(struct cdrom_multisession)))
1252				return -EFAULT;
1253#ifdef AZT_DEBUG
1254			if (ms.addr_format == CDROM_MSF)
1255				printk
1256				    ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
1257				     ms.xa_flag, ms.addr.msf.minute,
1258				     ms.addr.msf.second, ms.addr.msf.frame,
1259				     DiskInfo.lastSession.min,
1260				     DiskInfo.lastSession.sec,
1261				     DiskInfo.lastSession.frame);
1262			else
1263				printk
1264				    ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
1265				     ms.xa_flag, ms.addr.lba,
1266				     DiskInfo.lastSession.min,
1267				     DiskInfo.lastSession.sec,
1268				     DiskInfo.lastSession.frame);
1269#endif
1270			return 0;
1271		}
1272	case CDROMPLAYTRKIND:	/* Play a track.  This currently ignores index. */
1273		if (copy_from_user(&ti, argp, sizeof ti))
1274			return -EFAULT;
1275		if (ti.cdti_trk0 < DiskInfo.first
1276		    || ti.cdti_trk0 > DiskInfo.last
1277		    || ti.cdti_trk1 < ti.cdti_trk0) {
1278			return -EINVAL;
1279		}
1280		if (ti.cdti_trk1 > DiskInfo.last)
1281			ti.cdti_trk1 = DiskInfo.last;
1282		azt_Play.start = Toc[ti.cdti_trk0].diskTime;
1283		azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
1284#ifdef AZT_DEBUG
1285		printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
1286		       azt_Play.start.min, azt_Play.start.sec,
1287		       azt_Play.start.frame, azt_Play.end.min,
1288		       azt_Play.end.sec, azt_Play.end.frame);
1289#endif
1290		i = aztPlay(&azt_Play);
1291		if (i < 0) {
1292			aztAudioStatus = CDROM_AUDIO_ERROR;
1293			return -EIO;
1294		}
1295		aztAudioStatus = CDROM_AUDIO_PLAY;
1296		break;
1297	case CDROMPLAYMSF:	/* Play starting at the given MSF address. */
1298/*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
1299		{ if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
1300		  STEN_LOW;
1301		  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1302		}
1303*/
1304		if (copy_from_user(&msf, argp, sizeof msf))
1305			return -EFAULT;
1306		/* convert to bcd */
1307		azt_bin2bcd(&msf.cdmsf_min0);
1308		azt_bin2bcd(&msf.cdmsf_sec0);
1309		azt_bin2bcd(&msf.cdmsf_frame0);
1310		azt_bin2bcd(&msf.cdmsf_min1);
1311		azt_bin2bcd(&msf.cdmsf_sec1);
1312		azt_bin2bcd(&msf.cdmsf_frame1);
1313		azt_Play.start.min = msf.cdmsf_min0;
1314		azt_Play.start.sec = msf.cdmsf_sec0;
1315		azt_Play.start.frame = msf.cdmsf_frame0;
1316		azt_Play.end.min = msf.cdmsf_min1;
1317		azt_Play.end.sec = msf.cdmsf_sec1;
1318		azt_Play.end.frame = msf.cdmsf_frame1;
1319#ifdef AZT_DEBUG
1320		printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
1321		       azt_Play.start.min, azt_Play.start.sec,
1322		       azt_Play.start.frame, azt_Play.end.min,
1323		       azt_Play.end.sec, azt_Play.end.frame);
1324#endif
1325		i = aztPlay(&azt_Play);
1326		if (i < 0) {
1327			aztAudioStatus = CDROM_AUDIO_ERROR;
1328			return -EIO;
1329		}
1330		aztAudioStatus = CDROM_AUDIO_PLAY;
1331		break;
1332
1333	case CDROMREADTOCHDR:	/* Read the table of contents header */
1334		tocHdr.cdth_trk0 = DiskInfo.first;
1335		tocHdr.cdth_trk1 = DiskInfo.last;
1336		if (copy_to_user(argp, &tocHdr, sizeof tocHdr))
1337			return -EFAULT;
1338		break;
1339	case CDROMREADTOCENTRY:	/* Read an entry in the table of contents */
1340		if (copy_from_user(&entry, argp, sizeof entry))
1341			return -EFAULT;
1342		if ((!aztTocUpToDate) || aztDiskChanged)
1343			aztUpdateToc();
1344		if (entry.cdte_track == CDROM_LEADOUT)
1345			tocPtr = &Toc[DiskInfo.last + 1];
1346		else if (entry.cdte_track > DiskInfo.last
1347			 || entry.cdte_track < DiskInfo.first) {
1348			return -EINVAL;
1349		} else
1350			tocPtr = &Toc[entry.cdte_track];
1351		entry.cdte_adr = tocPtr->ctrl_addr;
1352		entry.cdte_ctrl = tocPtr->ctrl_addr >> 4;
1353		if (entry.cdte_format == CDROM_LBA)
1354			entry.cdte_addr.lba =
1355			    azt_msf2hsg(&tocPtr->diskTime);
1356		else if (entry.cdte_format == CDROM_MSF) {
1357			entry.cdte_addr.msf.minute =
1358			    azt_bcd2bin(tocPtr->diskTime.min);
1359			entry.cdte_addr.msf.second =
1360			    azt_bcd2bin(tocPtr->diskTime.sec);
1361			entry.cdte_addr.msf.frame =
1362			    azt_bcd2bin(tocPtr->diskTime.frame);
1363		} else {
1364			return -EINVAL;
1365		}
1366		if (copy_to_user(argp, &entry, sizeof entry))
1367			return -EFAULT;
1368		break;
1369	case CDROMSUBCHNL:	/* Get subchannel info */
1370		if (copy_from_user
1371		    (&subchnl, argp, sizeof(struct cdrom_subchnl)))
1372			return -EFAULT;
1373		if (aztGetQChannelInfo(&qInfo) < 0) {
1374#ifdef AZT_DEBUG
1375			printk
1376			    ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",
1377			     cmd);
1378#endif
1379			return -EIO;
1380		}
1381		subchnl.cdsc_audiostatus = aztAudioStatus;
1382		subchnl.cdsc_adr = qInfo.ctrl_addr;
1383		subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
1384		subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
1385		subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
1386		if (subchnl.cdsc_format == CDROM_LBA) {
1387			subchnl.cdsc_absaddr.lba =
1388			    azt_msf2hsg(&qInfo.diskTime);
1389			subchnl.cdsc_reladdr.lba =
1390			    azt_msf2hsg(&qInfo.trackTime);
1391		} else {	/*default */
1392			subchnl.cdsc_format = CDROM_MSF;
1393			subchnl.cdsc_absaddr.msf.minute =
1394			    azt_bcd2bin(qInfo.diskTime.min);
1395			subchnl.cdsc_absaddr.msf.second =
1396			    azt_bcd2bin(qInfo.diskTime.sec);
1397			subchnl.cdsc_absaddr.msf.frame =
1398			    azt_bcd2bin(qInfo.diskTime.frame);
1399			subchnl.cdsc_reladdr.msf.minute =
1400			    azt_bcd2bin(qInfo.trackTime.min);
1401			subchnl.cdsc_reladdr.msf.second =
1402			    azt_bcd2bin(qInfo.trackTime.sec);
1403			subchnl.cdsc_reladdr.msf.frame =
1404			    azt_bcd2bin(qInfo.trackTime.frame);
1405		}
1406		if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl)))
1407			return -EFAULT;
1408		break;
1409	case CDROMVOLCTRL:	/* Volume control 
1410				   * With my Aztech CD268-01A volume control does not work, I can only
1411				   turn the channels on (any value !=0) or off (value==0). Maybe it
1412				   works better with your drive */
1413		if (copy_from_user(&volctrl, argp, sizeof(volctrl)))
1414			return -EFAULT;
1415		azt_Play.start.min = 0x21;
1416		azt_Play.start.sec = 0x84;
1417		azt_Play.start.frame = volctrl.channel0;
1418		azt_Play.end.min = volctrl.channel1;
1419		azt_Play.end.sec = volctrl.channel2;
1420		azt_Play.end.frame = volctrl.channel3;
1421		sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
1422		STEN_LOW_WAIT;
1423		break;
1424	case CDROMEJECT:
1425		aztUnlockDoor();	/* Assume user knows what they're doing */
1426		/* all drives can at least stop! */
1427		if (aztAudioStatus == CDROM_AUDIO_PLAY) {
1428			if (aztSendCmd(ACMD_STOP))
1429				RETURNM("azt_ioctl 10", -1);
1430			STEN_LOW_WAIT;
1431		}
1432		if (aztSendCmd(ACMD_EJECT))
1433			RETURNM("azt_ioctl 11", -1);
1434		STEN_LOW_WAIT;
1435		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1436		break;
1437	case CDROMEJECT_SW:
1438		azt_auto_eject = (char) arg;
1439		break;
1440	case CDROMRESET:
1441		outb(ACMD_SOFT_RESET, CMD_PORT);	/*send reset */
1442		STEN_LOW;
1443		if (inb(DATA_PORT) != AFL_OP_OK) {	/*OP_OK? */
1444			printk
1445			    ("aztcd: AZTECH CD-ROM drive does not respond\n");
1446		}
1447		break;
1448/*Take care, the following code is not compatible with other CD-ROM drivers,
1449  use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
1450  if you do not want to use it!
1451*/
1452#if AZT_PRIVATE_IOCTLS
1453	case CDROMREADCOOKED:	/*read data in mode 1 (2048 Bytes) */
1454	case CDROMREADRAW:	/*read data in mode 2 (2336 Bytes) */
1455		{
1456			if (copy_from_user(&msf, argp, sizeof msf))
1457				return -EFAULT;
1458			/* convert to bcd */
1459			azt_bin2bcd(&msf.cdmsf_min0);
1460			azt_bin2bcd(&msf.cdmsf_sec0);
1461			azt_bin2bcd(&msf.cdmsf_frame0);
1462			msf.cdmsf_min1 = 0;
1463			msf.cdmsf_sec1 = 0;
1464			msf.cdmsf_frame1 = 1;	/*read only one frame */
1465			azt_Play.start.min = msf.cdmsf_min0;
1466			azt_Play.start.sec = msf.cdmsf_sec0;
1467			azt_Play.start.frame = msf.cdmsf_frame0;
1468			azt_Play.end.min = msf.cdmsf_min1;
1469			azt_Play.end.sec = msf.cdmsf_sec1;
1470			azt_Play.end.frame = msf.cdmsf_frame1;
1471			if (cmd == CDROMREADRAW) {
1472				if (DiskInfo.xa) {
1473					return -1;	/*XA Disks can't be read raw */
1474				} else {
1475					if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play))
1476						return -1;
1477					DTEN_LOW;
1478					insb(DATA_PORT, buf, CD_FRAMESIZE_RAW);
1479					if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW))
1480						return -EFAULT;
1481				}
1482			} else
1483				/*CDROMREADCOOKED*/ {
1484				if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
1485					return -1;
1486				DTEN_LOW;
1487				insb(DATA_PORT, buf, CD_FRAMESIZE);
1488				if (copy_to_user(argp, &buf, CD_FRAMESIZE))
1489					return -EFAULT;
1490				}
1491		}
1492		break;
1493	case CDROMSEEK:	/*seek msf address */
1494		if (copy_from_user(&msf, argp, sizeof msf))
1495			return -EFAULT;
1496		/* convert to bcd */
1497		azt_bin2bcd(&msf.cdmsf_min0);
1498		azt_bin2bcd(&msf.cdmsf_sec0);
1499		azt_bin2bcd(&msf.cdmsf_frame0);
1500		azt_Play.start.min = msf.cdmsf_min0;
1501		azt_Play.start.sec = msf.cdmsf_sec0;
1502		azt_Play.start.frame = msf.cdmsf_frame0;
1503		if (aztSeek(&azt_Play))
1504			return -1;
1505		break;
1506#endif				/*end of incompatible code */
1507	case CDROMREADMODE1:	/*set read data in mode 1 */
1508		return aztSetDiskType(AZT_MODE_1);
1509	case CDROMREADMODE2:	/*set read data in mode 2 */
1510		return aztSetDiskType(AZT_MODE_2);
1511	default:
1512		return -EINVAL;
1513	}
1514#ifdef AZT_DEBUG
1515	printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n", cmd,
1516	       jiffies);
1517#endif
1518	return 0;
1519}
1520
1521/*
1522 * Take care of the different block sizes between cdrom and Linux.
1523 * When Linux gets variable block sizes this will probably go away.
1524 */
1525static void azt_transfer(void)
1526{
1527#ifdef AZT_TEST
1528	printk("aztcd: executing azt_transfer Time:%li\n", jiffies);
1529#endif
1530	if (!current_valid())
1531	        return;
1532
1533	while (CURRENT->nr_sectors) {
1534		int bn = CURRENT->sector / 4;
1535		int i;
1536		for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i);
1537		if (i < AZT_BUF_SIZ) {
1538			int offs = (i * 4 + (CURRENT->sector & 3)) * 512;
1539			int nr_sectors = 4 - (CURRENT->sector & 3);
1540			if (azt_buf_out != i) {
1541				azt_buf_out = i;
1542				if (azt_buf_bn[i] != bn) {
1543					azt_buf_out = -1;
1544					continue;
1545				}
1546			}
1547			if (nr_sectors > CURRENT->nr_sectors)
1548			    nr_sectors = CURRENT->nr_sectors;
1549			memcpy(CURRENT->buffer, azt_buf + offs,
1550				nr_sectors * 512);
1551			CURRENT->nr_sectors -= nr_sectors;
1552			CURRENT->sector += nr_sectors;
1553			CURRENT->buffer += nr_sectors * 512;
1554		} else {
1555			azt_buf_out = -1;
1556			break;
1557		}
1558	}
1559}
1560
1561static void do_aztcd_request(request_queue_t * q)
1562{
1563#ifdef AZT_TEST
1564	printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector,
1565	       CURRENT->nr_sectors, jiffies);
1566#endif
1567	if (DiskInfo.audio) {
1568		printk("aztcd: Error, tried to mount an Audio CD\n");
1569		end_request(CURRENT, 0);
1570		return;
1571	}
1572	azt_transfer_is_active = 1;
1573	while (current_valid()) {
1574		azt_transfer();
1575		if (CURRENT->nr_sectors == 0) {
1576			end_request(CURRENT, 1);
1577		} else {
1578			azt_buf_out = -1;	/* Want to read a block not in buffer */
1579			if (azt_state == AZT_S_IDLE) {
1580				if ((!aztTocUpToDate) || aztDiskChanged) {
1581					if (aztUpdateToc() < 0) {
1582						while (current_valid())
1583							end_request(CURRENT, 0);
1584						break;
1585					}
1586				}
1587				azt_state = AZT_S_START;
1588				AztTries = 5;
1589				SET_TIMER(azt_poll, HZ / 100);
1590			}
1591			break;
1592		}
1593	}
1594	azt_transfer_is_active = 0;
1595#ifdef AZT_TEST2
1596	printk
1597	    ("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n",
1598	     azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
1599	printk(" do_aztcd_request ends  Time:%li\n", jiffies);
1600#endif
1601}
1602
1603
1604static void azt_invalidate_buffers(void)
1605{
1606	int i;
1607
1608#ifdef AZT_DEBUG
1609	printk("aztcd: executing azt_invalidate_buffers\n");
1610#endif
1611	for (i = 0; i < AZT_BUF_SIZ; ++i)
1612		azt_buf_bn[i] = -1;
1613	azt_buf_out = -1;
1614}
1615
1616/*
1617 * Open the device special file.  Check that a disk is in.
1618 */
1619static int aztcd_open(struct inode *ip, struct file *fp)
1620{
1621	int st;
1622
1623#ifdef AZT_DEBUG
1624	printk("aztcd: starting aztcd_open\n");
1625#endif
1626
1627	if (aztPresent == 0)
1628		return -ENXIO;	/* no hardware */
1629
1630	if (!azt_open_count && azt_state == AZT_S_IDLE) {
1631		azt_invalidate_buffers();
1632
1633		st = getAztStatus();	/* check drive status */
1634		if (st == -1)
1635			goto err_out;	/* drive doesn't respond */
1636
1637		if (st & AST_DOOR_OPEN) {	/* close door, then get the status again. */
1638			printk("aztcd: Door Open?\n");
1639			aztCloseDoor();
1640			st = getAztStatus();
1641		}
1642
1643		if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) {	/*no disk in drive or changed */
1644			printk
1645			    ("aztcd: Disk Changed or No Disk in Drive?\n");
1646			aztTocUpToDate = 0;
1647		}
1648		if (aztUpdateToc())
1649			goto err_out;
1650
1651	}
1652	++azt_open_count;
1653	aztLockDoor();
1654
1655#ifdef AZT_DEBUG
1656	printk("aztcd: exiting aztcd_open\n");
1657#endif
1658	return 0;
1659
1660      err_out:
1661	return -EIO;
1662}
1663
1664
1665/*
1666 * On close, we flush all azt blocks from the buffer cache.
1667 */
1668static int aztcd_release(struct inode *inode, struct file *file)
1669{
1670#ifdef AZT_DEBUG
1671	printk("aztcd: executing aztcd_release\n");
1672	printk("inode: %p, device: %s    file: %p\n", inode,
1673	       inode->i_bdev->bd_disk->disk_name, file);
1674#endif
1675	if (!--azt_open_count) {
1676		azt_invalidate_buffers();
1677		aztUnlockDoor();
1678		if (azt_auto_eject)
1679			aztSendCmd(ACMD_EJECT);
1680		CLEAR_TIMER;
1681	}
1682	return 0;
1683}
1684
1685static struct gendisk *azt_disk;
1686
1687/*
1688 * Test for presence of drive and initialize it.  Called at boot time.
1689 */
1690
1691static in

Large files files are truncated, but you can click here to view the full file