aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cdrom/aztcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cdrom/aztcd.c')
-rw-r--r--drivers/cdrom/aztcd.c2494
1 files changed, 2494 insertions, 0 deletions
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
new file mode 100644
index 000000000000..43bf1e5dc38a
--- /dev/null
+++ b/drivers/cdrom/aztcd.c
@@ -0,0 +1,2494 @@
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 int __init aztcd_init(void)
1692{
1693 long int count, max_count;
1694 unsigned char result[50];
1695 int st;
1696 void* status = NULL;
1697 int i = 0;
1698 int ret = 0;
1699
1700 if (azt_port == 0) {
1701 printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization");
1702 return -EIO;
1703 }
1704
1705 printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM "
1706 "CD-ROM Driver\n");
1707 printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n");
1708 if (azt_port == -1) {
1709 printk
1710 ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n",
1711 AZT_VERSION);
1712 } else
1713 printk
1714 ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n",
1715 AZT_VERSION, azt_port);
1716 printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/"
1717 "Documentation/cdrom/aztcd\n");
1718
1719
1720#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */
1721 if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) {
1722 printk
1723 ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
1724 AZT_SW32_BASE_ADDR, AZT_SW32_INIT,
1725 AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG);
1726 return -EIO;
1727 } else {
1728 printk(KERN_INFO
1729 "aztcd: Soundwave32 card detected at %x Version %x\n",
1730 AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
1731 outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG);
1732 for (count = 0; count < 10000; count++); /*delay a bit */
1733 }
1734#endif
1735
1736 /* check for presence of drive */
1737
1738 if (azt_port == -1) { /* autoprobing for proprietary interface */
1739 for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) {
1740 azt_port = azt_port_auto[i];
1741 printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x"
1742 "\n", azt_port);
1743 /*proprietary interfaces need 4 bytes */
1744 if (!request_region(azt_port, 4, "aztcd")) {
1745 continue;
1746 }
1747 outb(POLLED, MODE_PORT);
1748 inb(CMD_PORT);
1749 inb(CMD_PORT);
1750 outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
1751
1752 aztTimeOutCount = 0;
1753 do {
1754 aztIndatum = inb(STATUS_PORT);
1755 aztTimeOutCount++;
1756 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1757 break;
1758 } while (aztIndatum & AFL_STATUS);
1759 if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */
1760 break;
1761 }
1762 else { /* Drive not found on this port - try next one */
1763 release_region(azt_port, 4);
1764 }
1765 }
1766 if ((azt_port_auto[i] == 0) || (i == 16)) {
1767 printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n");
1768 return -EIO;
1769 }
1770 } else { /* no autoprobing */
1771 if ((azt_port == 0x1f0) || (azt_port == 0x170))
1772 status = request_region(azt_port, 8, "aztcd"); /*IDE-interfaces need 8 bytes */
1773 else
1774 status = request_region(azt_port, 4, "aztcd"); /*proprietary interfaces need 4 bytes */
1775 if (!status) {
1776 printk(KERN_WARNING "aztcd: conflict, I/O port (%X) "
1777 "already used\n", azt_port);
1778 return -EIO;
1779 }
1780
1781 if ((azt_port == 0x1f0) || (azt_port == 0x170))
1782 SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
1783
1784 outb(POLLED, MODE_PORT);
1785 inb(CMD_PORT);
1786 inb(CMD_PORT);
1787 outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
1788
1789 aztTimeOutCount = 0;
1790 do {
1791 aztIndatum = inb(STATUS_PORT);
1792 aztTimeOutCount++;
1793 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1794 break;
1795 } while (aztIndatum & AFL_STATUS);
1796
1797 if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */
1798#ifndef MODULE
1799 if (azt_cont != 0x79) {
1800 printk(KERN_WARNING "aztcd: no AZTECH CD-ROM "
1801 "drive found-Try boot parameter aztcd="
1802 "<BaseAddress>,0x79\n");
1803 ret = -EIO;
1804 goto err_out;
1805 }
1806#else
1807 if (0) {
1808 }
1809#endif
1810 else {
1811 printk(KERN_INFO "aztcd: drive reset - "
1812 "please wait\n");
1813 for (count = 0; count < 50; count++) {
1814 inb(STATUS_PORT); /*removing all data from earlier tries */
1815 inb(DATA_PORT);
1816 }
1817 outb(POLLED, MODE_PORT);
1818 inb(CMD_PORT);
1819 inb(CMD_PORT);
1820 getAztStatus(); /*trap errors */
1821 outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */
1822 STEN_LOW;
1823 if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */
1824 printk(KERN_WARNING "aztcd: no AZTECH "
1825 "CD-ROM drive found\n");
1826 ret = -EIO;
1827 goto err_out;
1828 }
1829
1830 for (count = 0; count < AZT_TIMEOUT;
1831 count++)
1832 barrier(); /* Stop gcc 2.96 being smart */
1833 /* use udelay(), damnit -- AV */
1834
1835 if ((st = getAztStatus()) == -1) {
1836 printk(KERN_WARNING "aztcd: Drive Status"
1837 " Error Status=%x\n", st);
1838 ret = -EIO;
1839 goto err_out;
1840 }
1841#ifdef AZT_DEBUG
1842 printk(KERN_DEBUG "aztcd: Status = %x\n", st);
1843#endif
1844 outb(POLLED, MODE_PORT);
1845 inb(CMD_PORT);
1846 inb(CMD_PORT);
1847 outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */
1848 STEN_LOW;
1849 OP_OK;
1850 }
1851 }
1852 }
1853
1854 azt_init_end = 1;
1855 STEN_LOW;
1856 result[0] = inb(DATA_PORT); /*reading in a null byte??? */
1857 for (count = 1; count < 50; count++) { /*Reading version string */
1858 aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */
1859 do {
1860 aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */
1861 aztTimeOutCount++;
1862 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1863 break;
1864 } while (aztIndatum & AFL_STATUS);
1865 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1866 break; /*all chars read? */
1867 result[count] = inb(DATA_PORT);
1868 }
1869 if (count > 30)
1870 max_count = 30; /*print max.30 chars of the version string */
1871 else
1872 max_count = count;
1873 printk(KERN_INFO "aztcd: FirmwareVersion=");
1874 for (count = 1; count < max_count; count++)
1875 printk("%c", result[count]);
1876 printk("<<>> ");
1877
1878 if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) {
1879 printk("AZTECH drive detected\n");
1880 /*AZTECH*/}
1881 else if ((result[2] == 'C') && (result[3] == 'D')
1882 && (result[4] == 'D')) {
1883 printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */
1884 } else if ((result[1] == 0x03) && (result[2] == '5')) {
1885 printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */
1886 } else { /*OTHERS or none */
1887 printk("\nunknown drive or firmware version detected\n");
1888 printk
1889 ("aztcd may not run stable, if you want to try anyhow,\n");
1890 printk("boot with: aztcd=<BaseAddress>,0x79\n");
1891 if ((azt_cont != 0x79)) {
1892 printk("aztcd: FirmwareVersion=");
1893 for (count = 1; count < 5; count++)
1894 printk("%c", result[count]);
1895 printk("<<>> ");
1896 printk("Aborted\n");
1897 ret = -EIO;
1898 goto err_out;
1899 }
1900 }
1901 azt_disk = alloc_disk(1);
1902 if (!azt_disk)
1903 goto err_out;
1904
1905 if (register_blkdev(MAJOR_NR, "aztcd")) {
1906 ret = -EIO;
1907 goto err_out2;
1908 }
1909
1910 azt_queue = blk_init_queue(do_aztcd_request, &aztSpin);
1911 if (!azt_queue) {
1912 ret = -ENOMEM;
1913 goto err_out3;
1914 }
1915
1916 blk_queue_hardsect_size(azt_queue, 2048);
1917 azt_disk->major = MAJOR_NR;
1918 azt_disk->first_minor = 0;
1919 azt_disk->fops = &azt_fops;
1920 sprintf(azt_disk->disk_name, "aztcd");
1921 sprintf(azt_disk->devfs_name, "aztcd");
1922 azt_disk->queue = azt_queue;
1923 add_disk(azt_disk);
1924 azt_invalidate_buffers();
1925 aztPresent = 1;
1926 aztCloseDoor();
1927 return 0;
1928err_out3:
1929 unregister_blkdev(MAJOR_NR, "aztcd");
1930err_out2:
1931 put_disk(azt_disk);
1932err_out:
1933 if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
1934 SWITCH_IDE_MASTER;
1935 release_region(azt_port, 8); /*IDE-interface */
1936 } else
1937 release_region(azt_port, 4); /*proprietary interface */
1938 return ret;
1939
1940}
1941
1942static void __exit aztcd_exit(void)
1943{
1944 del_gendisk(azt_disk);
1945 put_disk(azt_disk);
1946 if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) {
1947 printk("What's that: can't unregister aztcd\n");
1948 return;
1949 }
1950 blk_cleanup_queue(azt_queue);
1951 if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
1952 SWITCH_IDE_MASTER;
1953 release_region(azt_port, 8); /*IDE-interface */
1954 } else
1955 release_region(azt_port, 4); /*proprietary interface */
1956 printk(KERN_INFO "aztcd module released.\n");
1957}
1958
1959module_init(aztcd_init);
1960module_exit(aztcd_exit);
1961
1962/*##########################################################################
1963 Aztcd State Machine: Controls Drive Operating State
1964 ##########################################################################
1965*/
1966static void azt_poll(void)
1967{
1968 int st = 0;
1969 int loop_ctl = 1;
1970 int skip = 0;
1971
1972 if (azt_error) {
1973 if (aztSendCmd(ACMD_GET_ERROR))
1974 RETURN("azt_poll 1");
1975 STEN_LOW;
1976 azt_error = inb(DATA_PORT) & 0xFF;
1977 printk("aztcd: I/O error 0x%02x\n", azt_error);
1978 azt_invalidate_buffers();
1979#ifdef WARN_IF_READ_FAILURE
1980 if (AztTries == 5)
1981 printk
1982 ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n",
1983 azt_next_bn);
1984#endif
1985 if (!AztTries--) {
1986 printk
1987 ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n",
1988 azt_next_bn);
1989 if (azt_transfer_is_active) {
1990 AztTries = 0;
1991 loop_ctl = 0;
1992 }
1993 if (current_valid())
1994 end_request(CURRENT, 0);
1995 AztTries = 5;
1996 }
1997 azt_error = 0;
1998 azt_state = AZT_S_STOP;
1999 }
2000
2001 while (loop_ctl) {
2002 loop_ctl = 0; /* each case must flip this back to 1 if we want
2003 to come back up here */
2004 switch (azt_state) {
2005
2006 case AZT_S_IDLE:
2007#ifdef AZT_TEST3
2008 if (azt_state != azt_state_old) {
2009 azt_state_old = azt_state;
2010 printk("AZT_S_IDLE\n");
2011 }
2012#endif
2013 return;
2014
2015 case AZT_S_START:
2016#ifdef AZT_TEST3
2017 if (azt_state != azt_state_old) {
2018 azt_state_old = azt_state;
2019 printk("AZT_S_START\n");
2020 }
2021#endif
2022 if (aztSendCmd(ACMD_GET_STATUS))
2023 RETURN("azt_poll 2"); /*result will be checked by aztStatus() */
2024 azt_state =
2025 azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
2026 AztTimeout = 3000;
2027 break;
2028
2029 case AZT_S_MODE:
2030#ifdef AZT_TEST3
2031 if (azt_state != azt_state_old) {
2032 azt_state_old = azt_state;
2033 printk("AZT_S_MODE\n");
2034 }
2035#endif
2036 if (!skip) {
2037 if ((st = aztStatus()) != -1) {
2038 if ((st & AST_DSK_CHG)
2039 || (st & AST_NOT_READY)) {
2040 aztDiskChanged = 1;
2041 aztTocUpToDate = 0;
2042 azt_invalidate_buffers();
2043 end_request(CURRENT, 0);
2044 printk
2045 ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
2046 }
2047 } else
2048 break;
2049 }
2050 skip = 0;
2051
2052 if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
2053 aztDiskChanged = 1;
2054 aztTocUpToDate = 0;
2055 printk
2056 ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
2057 end_request(CURRENT, 0);
2058 printk((st & AST_DOOR_OPEN) ?
2059 "aztcd: door open\n" :
2060 "aztcd: disk removed\n");
2061 if (azt_transfer_is_active) {
2062 azt_state = AZT_S_START;
2063 loop_ctl = 1; /* goto immediately */
2064 break;
2065 }
2066 azt_state = AZT_S_IDLE;
2067 while (current_valid())
2068 end_request(CURRENT, 0);
2069 return;
2070 }
2071
2072/* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
2073 outb(0x01, DATA_PORT);
2074 PA_OK;
2075 STEN_LOW;
2076*/
2077 if (aztSendCmd(ACMD_GET_STATUS))
2078 RETURN("azt_poll 4");
2079 STEN_LOW;
2080 azt_mode = 1;
2081 azt_state = AZT_S_READ;
2082 AztTimeout = 3000;
2083
2084 break;
2085
2086
2087 case AZT_S_READ:
2088#ifdef AZT_TEST3
2089 if (azt_state != azt_state_old) {
2090 azt_state_old = azt_state;
2091 printk("AZT_S_READ\n");
2092 }
2093#endif
2094 if (!skip) {
2095 if ((st = aztStatus()) != -1) {
2096 if ((st & AST_DSK_CHG)
2097 || (st & AST_NOT_READY)) {
2098 aztDiskChanged = 1;
2099 aztTocUpToDate = 0;
2100 azt_invalidate_buffers();
2101 printk
2102 ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
2103 end_request(CURRENT, 0);
2104 }
2105 } else
2106 break;
2107 }
2108
2109 skip = 0;
2110 if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
2111 aztDiskChanged = 1;
2112 aztTocUpToDate = 0;
2113 printk((st & AST_DOOR_OPEN) ?
2114 "aztcd: door open\n" :
2115 "aztcd: disk removed\n");
2116 if (azt_transfer_is_active) {
2117 azt_state = AZT_S_START;
2118 loop_ctl = 1;
2119 break;
2120 }
2121 azt_state = AZT_S_IDLE;
2122 while (current_valid())
2123 end_request(CURRENT, 0);
2124 return;
2125 }
2126
2127 if (current_valid()) {
2128 struct azt_Play_msf msf;
2129 int i;
2130 azt_next_bn = CURRENT->sector / 4;
2131 azt_hsg2msf(azt_next_bn, &msf.start);
2132 i = 0;
2133 /* find out in which track we are */
2134 while (azt_msf2hsg(&msf.start) >
2135 azt_msf2hsg(&Toc[++i].trackTime)) {
2136 };
2137 if (azt_msf2hsg(&msf.start) <
2138 azt_msf2hsg(&Toc[i].trackTime) -
2139 AZT_BUF_SIZ) {
2140 azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */
2141 /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */
2142 } else /* don't read beyond end of track */
2143#if AZT_MULTISESSION
2144 {
2145 azt_read_count =
2146 (azt_msf2hsg(&Toc[i].trackTime)
2147 / 4) * 4 -
2148 azt_msf2hsg(&msf.start);
2149 if (azt_read_count < 0)
2150 azt_read_count = 0;
2151 if (azt_read_count > AZT_BUF_SIZ)
2152 azt_read_count =
2153 AZT_BUF_SIZ;
2154 printk
2155 ("aztcd: warning - trying to read beyond end of track\n");
2156/* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
2157*/ }
2158#else
2159 {
2160 azt_read_count = AZT_BUF_SIZ;
2161 }
2162#endif
2163 msf.end.min = 0;
2164 msf.end.sec = 0;
2165 msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */
2166#ifdef AZT_TEST3
2167 printk
2168 ("---reading msf-address %x:%x:%x %x:%x:%x\n",
2169 msf.start.min, msf.start.sec,
2170 msf.start.frame, msf.end.min,
2171 msf.end.sec, msf.end.frame);
2172 printk
2173 ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n",
2174 azt_next_bn, azt_buf_in, azt_buf_out,
2175 azt_buf_bn[azt_buf_in]);
2176#endif
2177 if (azt_read_mode == AZT_MODE_2) {
2178 sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */
2179 } else {
2180 sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */
2181 }
2182 azt_state = AZT_S_DATA;
2183 AztTimeout = READ_TIMEOUT;
2184 } else {
2185 azt_state = AZT_S_STOP;
2186 loop_ctl = 1;
2187 break;
2188 }
2189
2190 break;
2191
2192
2193 case AZT_S_DATA:
2194#ifdef AZT_TEST3
2195 if (azt_state != azt_state_old) {
2196 azt_state_old = azt_state;
2197 printk("AZT_S_DATA\n");
2198 }
2199#endif
2200
2201 st = inb(STATUS_PORT) & AFL_STATUSorDATA;
2202
2203 switch (st) {
2204
2205 case AFL_DATA:
2206#ifdef AZT_TEST3
2207 if (st != azt_st_old) {
2208 azt_st_old = st;
2209 printk("---AFL_DATA st:%x\n", st);
2210 }
2211#endif
2212 if (!AztTries--) {
2213 printk
2214 ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n",
2215 azt_next_bn);
2216 if (azt_transfer_is_active) {
2217 AztTries = 0;
2218 break;
2219 }
2220 if (current_valid())
2221 end_request(CURRENT, 0);
2222 AztTries = 5;
2223 }
2224 azt_state = AZT_S_START;
2225 AztTimeout = READ_TIMEOUT;
2226 loop_ctl = 1;
2227 break;
2228
2229 case AFL_STATUSorDATA:
2230#ifdef AZT_TEST3
2231 if (st != azt_st_old) {
2232 azt_st_old = st;
2233 printk
2234 ("---AFL_STATUSorDATA st:%x\n",
2235 st);
2236 }
2237#endif
2238 break;
2239
2240 default:
2241#ifdef AZT_TEST3
2242 if (st != azt_st_old) {
2243 azt_st_old = st;
2244 printk("---default: st:%x\n", st);
2245 }
2246#endif
2247 AztTries = 5;
2248 if (!current_valid() && azt_buf_in == azt_buf_out) {
2249 azt_state = AZT_S_STOP;
2250 loop_ctl = 1;
2251 break;
2252 }
2253 if (azt_read_count <= 0)
2254 printk
2255 ("aztcd: warning - try to read 0 frames\n");
2256 while (azt_read_count) { /*??? fast read ahead loop */
2257 azt_buf_bn[azt_buf_in] = -1;
2258 DTEN_LOW; /*??? unsolved problem, very
2259 seldom we get timeouts
2260 here, don't now the real
2261 reason. With my drive this
2262 sometimes also happens with
2263 Aztech's original driver under
2264 DOS. Is it a hardware bug?
2265 I tried to recover from such
2266 situations here. Zimmermann */
2267 if (aztTimeOutCount >= AZT_TIMEOUT) {
2268 printk
2269 ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n",
2270 azt_read_count,
2271 CURRENT->nr_sectors,
2272 azt_buf_in);
2273 printk
2274 ("azt_transfer_is_active:%x\n",
2275 azt_transfer_is_active);
2276 azt_read_count = 0;
2277 azt_state = AZT_S_STOP;
2278 loop_ctl = 1;
2279 end_request(CURRENT, 1); /*should we have here (1) or (0)? */
2280 } else {
2281 if (azt_read_mode ==
2282 AZT_MODE_2) {
2283 insb(DATA_PORT,
2284 azt_buf +
2285 CD_FRAMESIZE_RAW
2286 * azt_buf_in,
2287 CD_FRAMESIZE_RAW);
2288 } else {
2289 insb(DATA_PORT,
2290 azt_buf +
2291 CD_FRAMESIZE *
2292 azt_buf_in,
2293 CD_FRAMESIZE);
2294 }
2295 azt_read_count--;
2296#ifdef AZT_TEST3
2297 printk
2298 ("AZT_S_DATA; ---I've read data- read_count: %d\n",
2299 azt_read_count);
2300 printk
2301 ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n",
2302 azt_next_bn,
2303 azt_buf_in,
2304 azt_buf_out,
2305 azt_buf_bn
2306 [azt_buf_in]);
2307#endif
2308 azt_buf_bn[azt_buf_in] =
2309 azt_next_bn++;
2310 if (azt_buf_out == -1)
2311 azt_buf_out =
2312 azt_buf_in;
2313 azt_buf_in =
2314 azt_buf_in + 1 ==
2315 AZT_BUF_SIZ ? 0 :
2316 azt_buf_in + 1;
2317 }
2318 }
2319 if (!azt_transfer_is_active) {
2320 while (current_valid()) {
2321 azt_transfer();
2322 if (CURRENT->nr_sectors ==
2323 0)
2324 end_request(CURRENT, 1);
2325 else
2326 break;
2327 }
2328 }
2329
2330 if (current_valid()
2331 && (CURRENT->sector / 4 < azt_next_bn
2332 || CURRENT->sector / 4 >
2333 azt_next_bn + AZT_BUF_SIZ)) {
2334 azt_state = AZT_S_STOP;
2335 loop_ctl = 1;
2336 break;
2337 }
2338 AztTimeout = READ_TIMEOUT;
2339 if (azt_read_count == 0) {
2340 azt_state = AZT_S_STOP;
2341 loop_ctl = 1;
2342 break;
2343 }
2344 break;
2345 }
2346 break;
2347
2348
2349 case AZT_S_STOP:
2350#ifdef AZT_TEST3
2351 if (azt_state != azt_state_old) {
2352 azt_state_old = azt_state;
2353 printk("AZT_S_STOP\n");
2354 }
2355#endif
2356 if (azt_read_count != 0)
2357 printk("aztcd: discard data=%x frames\n",
2358 azt_read_count);
2359 while (azt_read_count != 0) {
2360 int i;
2361 if (!(inb(STATUS_PORT) & AFL_DATA)) {
2362 if (azt_read_mode == AZT_MODE_2)
2363 for (i = 0;
2364 i < CD_FRAMESIZE_RAW;
2365 i++)
2366 inb(DATA_PORT);
2367 else
2368 for (i = 0;
2369 i < CD_FRAMESIZE; i++)
2370 inb(DATA_PORT);
2371 }
2372 azt_read_count--;
2373 }
2374 if (aztSendCmd(ACMD_GET_STATUS))
2375 RETURN("azt_poll 5");
2376 azt_state = AZT_S_STOPPING;
2377 AztTimeout = 1000;
2378 break;
2379
2380 case AZT_S_STOPPING:
2381#ifdef AZT_TEST3
2382 if (azt_state != azt_state_old) {
2383 azt_state_old = azt_state;
2384 printk("AZT_S_STOPPING\n");
2385 }
2386#endif
2387
2388 if ((st = aztStatus()) == -1 && AztTimeout)
2389 break;
2390
2391 if ((st != -1)
2392 && ((st & AST_DSK_CHG)
2393 || (st & AST_NOT_READY))) {
2394 aztDiskChanged = 1;
2395 aztTocUpToDate = 0;
2396 azt_invalidate_buffers();
2397 printk
2398 ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
2399 end_request(CURRENT, 0);
2400 }
2401
2402#ifdef AZT_TEST3
2403 printk("CURRENT_VALID %d azt_mode %d\n",
2404 current_valid(), azt_mode);
2405#endif
2406
2407 if (current_valid()) {
2408 if (st != -1) {
2409 if (azt_mode == 1) {
2410 azt_state = AZT_S_READ;
2411 loop_ctl = 1;
2412 skip = 1;
2413 break;
2414 } else {
2415 azt_state = AZT_S_MODE;
2416 loop_ctl = 1;
2417 skip = 1;
2418 break;
2419 }
2420 } else {
2421 azt_state = AZT_S_START;
2422 AztTimeout = 1;
2423 }
2424 } else {
2425 azt_state = AZT_S_IDLE;
2426 return;
2427 }
2428 break;
2429
2430 default:
2431 printk("aztcd: invalid state %d\n", azt_state);
2432 return;
2433 } /* case */
2434 } /* while */
2435
2436
2437 if (!AztTimeout--) {
2438 printk("aztcd: timeout in state %d\n", azt_state);
2439 azt_state = AZT_S_STOP;
2440 if (aztSendCmd(ACMD_STOP))
2441 RETURN("azt_poll 6");
2442 STEN_LOW_WAIT;
2443 };
2444
2445 SET_TIMER(azt_poll, HZ / 100);
2446}
2447
2448
2449/*###########################################################################
2450 * Miscellaneous support functions
2451 ###########################################################################
2452*/
2453static void azt_hsg2msf(long hsg, struct msf *msf)
2454{
2455 hsg += 150;
2456 msf->min = hsg / 4500;
2457 hsg %= 4500;
2458 msf->sec = hsg / 75;
2459 msf->frame = hsg % 75;
2460#ifdef AZT_DEBUG
2461 if (msf->min >= 70)
2462 printk("aztcd: Error hsg2msf address Minutes\n");
2463 if (msf->sec >= 60)
2464 printk("aztcd: Error hsg2msf address Seconds\n");
2465 if (msf->frame >= 75)
2466 printk("aztcd: Error hsg2msf address Frames\n");
2467#endif
2468 azt_bin2bcd(&msf->min); /* convert to BCD */
2469 azt_bin2bcd(&msf->sec);
2470 azt_bin2bcd(&msf->frame);
2471}
2472
2473static long azt_msf2hsg(struct msf *mp)
2474{
2475 return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75
2476 + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET;
2477}
2478
2479static void azt_bin2bcd(unsigned char *p)
2480{
2481 int u, t;
2482
2483 u = *p % 10;
2484 t = *p / 10;
2485 *p = u | (t << 4);
2486}
2487
2488static int azt_bcd2bin(unsigned char bcd)
2489{
2490 return (bcd >> 4) * 10 + (bcd & 0xF);
2491}
2492
2493MODULE_LICENSE("GPL");
2494MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR);