]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/cdrom/aztcd.c
rtc-rs5c313.c: add error handling to avoid hardware hangup
[mirror_ubuntu-zesty-kernel.git] / drivers / cdrom / aztcd.c
CommitLineData
1da177e4
LT
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>
1da177e4
LT
173#include <linux/mm.h>
174#include <linux/timer.h>
175#include <linux/fs.h>
176#include <linux/kernel.h>
177#include <linux/cdrom.h>
178#include <linux/ioport.h>
179#include <linux/string.h>
180#include <linux/major.h>
181
182#include <linux/init.h>
183
184#include <asm/system.h>
185#include <asm/io.h>
186
187#include <asm/uaccess.h>
188
189/*###########################################################################
190 Defines
191 ###########################################################################
192*/
193
194#define MAJOR_NR AZTECH_CDROM_MAJOR
195#define QUEUE (azt_queue)
196#define CURRENT elv_next_request(azt_queue)
197#define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \
198 delay_timer.function = (void *) (func); \
199 add_timer(&delay_timer);
200
201#define CLEAR_TIMER del_timer(&delay_timer);
202
203#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\
204 return value;}
205#define RETURN(message) {printk("aztcd: Warning: %s failed\n",message);\
206 return;}
207
208/* Macros to switch the IDE-interface to the slave device and back to the master*/
209#define SWITCH_IDE_SLAVE outb_p(0xa0,azt_port+6); \
210 outb_p(0x10,azt_port+6); \
211 outb_p(0x00,azt_port+7); \
212 outb_p(0x10,azt_port+6);
213#define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6);
214
215
216#if 0
217#define AZT_TEST
218#define AZT_TEST1 /* <int-..> */
219#define AZT_TEST2 /* do_aztcd_request */
220#define AZT_TEST3 /* AZT_S_state */
221#define AZT_TEST4 /* QUICK_LOOP-counter */
222#define AZT_TEST5 /* port(1) state */
223#define AZT_DEBUG
224#define AZT_DEBUG_MULTISESSION
225#endif
226
227static struct request_queue *azt_queue;
228
229static int current_valid(void)
230{
231 return CURRENT &&
232 CURRENT->cmd == READ &&
233 CURRENT->sector != -1;
234}
235
236#define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
237#define AZT_BUF_SIZ 16
238
239#define READ_TIMEOUT 3000
240
241#define azt_port aztcd /*needed for the modutils */
242
243/*##########################################################################
244 Type Definitions
245 ##########################################################################
246*/
247enum azt_state_e { AZT_S_IDLE, /* 0 */
248 AZT_S_START, /* 1 */
249 AZT_S_MODE, /* 2 */
250 AZT_S_READ, /* 3 */
251 AZT_S_DATA, /* 4 */
252 AZT_S_STOP, /* 5 */
253 AZT_S_STOPPING /* 6 */
254};
255enum azt_read_modes { AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware */
256 AZT_MODE_1, /*read mode for normal CD-ROMs */
257 AZT_MODE_2 /*read mode for XA CD-ROMs */
258};
259
260/*##########################################################################
261 Global Variables
262 ##########################################################################
263*/
264static int aztPresent = 0;
265
266static volatile int azt_transfer_is_active = 0;
267
268static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ]; /*buffer for block size conversion */
269#if AZT_PRIVATE_IOCTLS
270static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls */
271#endif
272
273static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
274static volatile int azt_buf_in, azt_buf_out = -1;
275static volatile int azt_error = 0;
276static int azt_open_count = 0;
277static volatile enum azt_state_e azt_state = AZT_S_IDLE;
278#ifdef AZT_TEST3
279static volatile enum azt_state_e azt_state_old = AZT_S_STOP;
280static volatile int azt_st_old = 0;
281#endif
282static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
283
284static int azt_mode = -1;
285static volatile int azt_read_count = 1;
286
287static int azt_port = AZT_BASE_ADDR;
288
289module_param(azt_port, int, 0);
290
291static int azt_port_auto[16] = AZT_BASE_AUTO;
292
293static char azt_cont = 0;
294static char azt_init_end = 0;
295static char azt_auto_eject = AZT_AUTO_EJECT;
296
297static int AztTimeout, AztTries;
298static DECLARE_WAIT_QUEUE_HEAD(azt_waitq);
8d06afab 299static DEFINE_TIMER(delay_timer, NULL, 0, 0);
1da177e4
LT
300
301static struct azt_DiskInfo DiskInfo;
302static struct azt_Toc Toc[MAX_TRACKS];
303static struct azt_Play_msf azt_Play;
304
305static int aztAudioStatus = CDROM_AUDIO_NO_STATUS;
306static char aztDiskChanged = 1;
307static char aztTocUpToDate = 0;
308
309static unsigned char aztIndatum;
310static unsigned long aztTimeOutCount;
311static int aztCmd = 0;
312
313static DEFINE_SPINLOCK(aztSpin);
314
315/*###########################################################################
316 Function Prototypes
317 ###########################################################################
318*/
319/* CDROM Drive Low Level I/O Functions */
320static void aztStatTimer(void);
321
322/* CDROM Drive Command Functions */
323static int aztGetDiskInfo(void);
324#if AZT_MULTISESSION
325static int aztGetMultiDiskInfo(void);
326#endif
327static int aztGetToc(int multi);
328
329/* Kernel Interface Functions */
330static int check_aztcd_media_change(struct gendisk *disk);
331static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
332 unsigned long arg);
333static int aztcd_open(struct inode *ip, struct file *fp);
334static int aztcd_release(struct inode *inode, struct file *file);
335
336static struct block_device_operations azt_fops = {
337 .owner = THIS_MODULE,
338 .open = aztcd_open,
339 .release = aztcd_release,
340 .ioctl = aztcd_ioctl,
341 .media_changed = check_aztcd_media_change,
342};
343
344/* Aztcd State Machine: Controls Drive Operating State */
345static void azt_poll(void);
346
347/* Miscellaneous support functions */
348static void azt_hsg2msf(long hsg, struct msf *msf);
349static long azt_msf2hsg(struct msf *mp);
350static void azt_bin2bcd(unsigned char *p);
351static int azt_bcd2bin(unsigned char bcd);
352
353/*##########################################################################
354 CDROM Drive Low Level I/O Functions
355 ##########################################################################
356*/
357/* Macros for the drive hardware interface handshake, these macros use
358 busy waiting */
359/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
360# define OP_OK op_ok()
361static void op_ok(void)
362{
363 aztTimeOutCount = 0;
364 do {
365 aztIndatum = inb(DATA_PORT);
366 aztTimeOutCount++;
367 if (aztTimeOutCount >= AZT_TIMEOUT) {
368 printk("aztcd: Error Wait OP_OK\n");
369 break;
370 }
371 } while (aztIndatum != AFL_OP_OK);
372}
373
374/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
375#if 0
376# define PA_OK pa_ok()
377static void pa_ok(void)
378{
379 aztTimeOutCount = 0;
380 do {
381 aztIndatum = inb(DATA_PORT);
382 aztTimeOutCount++;
383 if (aztTimeOutCount >= AZT_TIMEOUT) {
384 printk("aztcd: Error Wait PA_OK\n");
385 break;
386 }
387 } while (aztIndatum != AFL_PA_OK);
388}
389#endif
390
391/* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/
392# define STEN_LOW sten_low()
393static void sten_low(void)
394{
395 aztTimeOutCount = 0;
396 do {
397 aztIndatum = inb(STATUS_PORT);
398 aztTimeOutCount++;
399 if (aztTimeOutCount >= AZT_TIMEOUT) {
400 if (azt_init_end)
401 printk
402 ("aztcd: Error Wait STEN_LOW commands:%x\n",
403 aztCmd);
404 break;
405 }
406 } while (aztIndatum & AFL_STATUS);
407}
408
409/* Wait for DTEN=Low = handshake signal 'Data available'*/
410# define DTEN_LOW dten_low()
411static void dten_low(void)
412{
413 aztTimeOutCount = 0;
414 do {
415 aztIndatum = inb(STATUS_PORT);
416 aztTimeOutCount++;
417 if (aztTimeOutCount >= AZT_TIMEOUT) {
418 printk("aztcd: Error Wait DTEN_OK\n");
419 break;
420 }
421 } while (aztIndatum & AFL_DATA);
422}
423
424/*
425 * Macro for timer wait on STEN=Low, should only be used for 'slow' commands;
426 * may cause kernel panic when used in the wrong place
427*/
428#define STEN_LOW_WAIT statusAzt()
429static void statusAzt(void)
430{
431 AztTimeout = AZT_STATUS_DELAY;
432 SET_TIMER(aztStatTimer, HZ / 100);
433 sleep_on(&azt_waitq);
434 if (AztTimeout <= 0)
435 printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",
436 aztCmd);
437 return;
438}
439
440static void aztStatTimer(void)
441{
442 if (!(inb(STATUS_PORT) & AFL_STATUS)) {
443 wake_up(&azt_waitq);
444 return;
445 }
446 AztTimeout--;
447 if (AztTimeout <= 0) {
448 wake_up(&azt_waitq);
449 printk("aztcd: Error aztStatTimer: Timeout\n");
450 return;
451 }
452 SET_TIMER(aztStatTimer, HZ / 100);
453}
454
455/*##########################################################################
456 CDROM Drive Command Functions
457 ##########################################################################
458*/
459/*
460 * Send a single command, return -1 on error, else 0
461*/
462static int aztSendCmd(int cmd)
463{
464 unsigned char data;
465 int retry;
466
467#ifdef AZT_DEBUG
468 printk("aztcd: Executing command %x\n", cmd);
469#endif
470
471 if ((azt_port == 0x1f0) || (azt_port == 0x170))
472 SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
473
474 aztCmd = cmd;
475 outb(POLLED, MODE_PORT);
476 do {
477 if (inb(STATUS_PORT) & AFL_STATUS)
478 break;
479 inb(DATA_PORT); /* if status left from last command, read and */
480 } while (1); /* discard it */
481 do {
482 if (inb(STATUS_PORT) & AFL_DATA)
483 break;
484 inb(DATA_PORT); /* if data left from last command, read and */
485 } while (1); /* discard it */
486 for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
487 outb((unsigned char) cmd, CMD_PORT);
488 STEN_LOW;
489 data = inb(DATA_PORT);
490 if (data == AFL_OP_OK) {
491 return 0;
492 } /*OP_OK? */
493 if (data == AFL_OP_ERR) {
494 STEN_LOW;
495 data = inb(DATA_PORT);
496 printk
497 ("### Error 1 aztcd: aztSendCmd %x Error Code %x\n",
498 cmd, data);
499 }
500 }
501 if (retry >= AZT_RETRY_ATTEMPTS) {
502 printk("### Error 2 aztcd: aztSendCmd %x \n", cmd);
503 azt_error = 0xA5;
504 }
505 RETURNM("aztSendCmd", -1);
506}
507
508/*
509 * Send a play or read command to the drive, return -1 on error, else 0
510*/
511static int sendAztCmd(int cmd, struct azt_Play_msf *params)
512{
513 unsigned char data;
514 int retry;
515
516#ifdef AZT_DEBUG
517 printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n",
518 params->start.min, params->start.sec, params->start.frame,
519 params->end.min, params->end.sec, params->end.frame);
520#endif
521 for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
522 aztSendCmd(cmd);
523 outb(params->start.min, CMD_PORT);
524 outb(params->start.sec, CMD_PORT);
525 outb(params->start.frame, CMD_PORT);
526 outb(params->end.min, CMD_PORT);
527 outb(params->end.sec, CMD_PORT);
528 outb(params->end.frame, CMD_PORT);
529 STEN_LOW;
530 data = inb(DATA_PORT);
531 if (data == AFL_PA_OK) {
532 return 0;
533 } /*PA_OK ? */
534 if (data == AFL_PA_ERR) {
535 STEN_LOW;
536 data = inb(DATA_PORT);
537 printk
538 ("### Error 1 aztcd: sendAztCmd %x Error Code %x\n",
539 cmd, data);
540 }
541 }
542 if (retry >= AZT_RETRY_ATTEMPTS) {
543 printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd);
544 azt_error = 0xA5;
545 }
546 RETURNM("sendAztCmd", -1);
547}
548
549/*
550 * Send a seek command to the drive, return -1 on error, else 0
551*/
552static int aztSeek(struct azt_Play_msf *params)
553{
554 unsigned char data;
555 int retry;
556
557#ifdef AZT_DEBUG
558 printk("aztcd: aztSeek %02x:%02x:%02x\n",
559 params->start.min, params->start.sec, params->start.frame);
560#endif
561 for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
562 aztSendCmd(ACMD_SEEK);
563 outb(params->start.min, CMD_PORT);
564 outb(params->start.sec, CMD_PORT);
565 outb(params->start.frame, CMD_PORT);
566 STEN_LOW;
567 data = inb(DATA_PORT);
568 if (data == AFL_PA_OK) {
569 return 0;
570 } /*PA_OK ? */
571 if (data == AFL_PA_ERR) {
572 STEN_LOW;
573 data = inb(DATA_PORT);
574 printk("### Error 1 aztcd: aztSeek\n");
575 }
576 }
577 if (retry >= AZT_RETRY_ATTEMPTS) {
578 printk("### Error 2 aztcd: aztSeek\n ");
579 azt_error = 0xA5;
580 }
581 RETURNM("aztSeek", -1);
582}
583
584/* Send a Set Disk Type command
585 does not seem to work with Aztech drives, behavior is completely indepen-
586 dent on which mode is set ???
587*/
588static int aztSetDiskType(int type)
589{
590 unsigned char data;
591 int retry;
592
593#ifdef AZT_DEBUG
594 printk("aztcd: set disk type command: type= %i\n", type);
595#endif
596 for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
597 aztSendCmd(ACMD_SET_DISK_TYPE);
598 outb(type, CMD_PORT);
599 STEN_LOW;
600 data = inb(DATA_PORT);
601 if (data == AFL_PA_OK) { /*PA_OK ? */
602 azt_read_mode = type;
603 return 0;
604 }
605 if (data == AFL_PA_ERR) {
606 STEN_LOW;
607 data = inb(DATA_PORT);
608 printk
609 ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",
610 type, data);
611 }
612 }
613 if (retry >= AZT_RETRY_ATTEMPTS) {
614 printk("### Error 2 aztcd: aztSetDiskType %x\n ", type);
615 azt_error = 0xA5;
616 }
617 RETURNM("aztSetDiskType", -1);
618}
619
620
621/* used in azt_poll to poll the status, expects another program to issue a
622 * ACMD_GET_STATUS directly before
623 */
624static int aztStatus(void)
625{
626 int st;
627/* int i;
628
629 i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ???
630 if (!i)
631*/ STEN_LOW;
632 if (aztTimeOutCount < AZT_TIMEOUT) {
633 st = inb(DATA_PORT) & 0xFF;
634 return st;
635 } else
636 RETURNM("aztStatus", -1);
637}
638
639/*
640 * Get the drive status
641 */
642static int getAztStatus(void)
643{
644 int st;
645
646 if (aztSendCmd(ACMD_GET_STATUS))
647 RETURNM("getAztStatus 1", -1);
648 STEN_LOW;
649 st = inb(DATA_PORT) & 0xFF;
650#ifdef AZT_DEBUG
651 printk("aztcd: Status = %x\n", st);
652#endif
653 if ((st == 0xFF) || (st & AST_CMD_CHECK)) {
654 printk
655 ("aztcd: AST_CMD_CHECK error or no status available\n");
656 return -1;
657 }
658
659 if (((st & AST_MODE_BITS) != AST_BUSY)
660 && (aztAudioStatus == CDROM_AUDIO_PLAY))
661 /* XXX might be an error? look at q-channel? */
662 aztAudioStatus = CDROM_AUDIO_COMPLETED;
663
664 if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) {
665 aztDiskChanged = 1;
666 aztTocUpToDate = 0;
667 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
668 }
669 return st;
670}
671
672
673/*
674 * Send a 'Play' command and get the status. Use only from the top half.
675 */
676static int aztPlay(struct azt_Play_msf *arg)
677{
678 if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0)
679 RETURNM("aztPlay", -1);
680 return 0;
681}
682
683/*
684 * Subroutines to automatically close the door (tray) and
685 * lock it closed when the cd is mounted. Leave the tray
686 * locking as an option
687 */
688static void aztCloseDoor(void)
689{
690 aztSendCmd(ACMD_CLOSE);
691 STEN_LOW;
692 return;
693}
694
695static void aztLockDoor(void)
696{
697#if AZT_ALLOW_TRAY_LOCK
698 aztSendCmd(ACMD_LOCK);
699 STEN_LOW;
700#endif
701 return;
702}
703
704static void aztUnlockDoor(void)
705{
706#if AZT_ALLOW_TRAY_LOCK
707 aztSendCmd(ACMD_UNLOCK);
708 STEN_LOW;
709#endif
710 return;
711}
712
713/*
714 * Read a value from the drive. Should return quickly, so a busy wait
715 * is used to avoid excessive rescheduling. The read command itself must
716 * be issued with aztSendCmd() directly before
717 */
718static int aztGetValue(unsigned char *result)
719{
720 int s;
721
722 STEN_LOW;
723 if (aztTimeOutCount >= AZT_TIMEOUT) {
724 printk("aztcd: aztGetValue timeout\n");
725 return -1;
726 }
727 s = inb(DATA_PORT) & 0xFF;
728 *result = (unsigned char) s;
729 return 0;
730}
731
732/*
733 * Read the current Q-channel info. Also used for reading the
734 * table of contents.
735 */
736static int aztGetQChannelInfo(struct azt_Toc *qp)
737{
738 unsigned char notUsed;
739 int st;
740
741#ifdef AZT_DEBUG
742 printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies);
743#endif
744 if ((st = getAztStatus()) == -1)
745 RETURNM("aztGetQChannelInfo 1", -1);
746 if (aztSendCmd(ACMD_GET_Q_CHANNEL))
747 RETURNM("aztGetQChannelInfo 2", -1);
748 /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */
749 if (aztGetValue(&notUsed))
750 RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */
751 if ((st & AST_MODE_BITS) == AST_INITIAL) {
752 qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */
753 qp->track = 0; /* only one byte with Aztech drives */
754 qp->pointIndex = 0;
755 qp->trackTime.min = 0;
756 qp->trackTime.sec = 0;
757 qp->trackTime.frame = 0;
758 qp->diskTime.min = 0;
759 qp->diskTime.sec = 0;
760 qp->diskTime.frame = 0;
761 return 0;
762 } else {
763 if (aztGetValue(&qp->ctrl_addr) < 0)
764 RETURNM("aztGetQChannelInfo 4", -1);
765 if (aztGetValue(&qp->track) < 0)
766 RETURNM("aztGetQChannelInfo 4", -1);
767 if (aztGetValue(&qp->pointIndex) < 0)
768 RETURNM("aztGetQChannelInfo 4", -1);
769 if (aztGetValue(&qp->trackTime.min) < 0)
770 RETURNM("aztGetQChannelInfo 4", -1);
771 if (aztGetValue(&qp->trackTime.sec) < 0)
772 RETURNM("aztGetQChannelInfo 4", -1);
773 if (aztGetValue(&qp->trackTime.frame) < 0)
774 RETURNM("aztGetQChannelInfo 4", -1);
775 if (aztGetValue(&notUsed) < 0)
776 RETURNM("aztGetQChannelInfo 4", -1);
777 if (aztGetValue(&qp->diskTime.min) < 0)
778 RETURNM("aztGetQChannelInfo 4", -1);
779 if (aztGetValue(&qp->diskTime.sec) < 0)
780 RETURNM("aztGetQChannelInfo 4", -1);
781 if (aztGetValue(&qp->diskTime.frame) < 0)
782 RETURNM("aztGetQChannelInfo 4", -1);
783 }
784#ifdef AZT_DEBUG
785 printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies);
786#endif
787 return 0;
788}
789
790/*
791 * Read the table of contents (TOC) and TOC header if necessary
792 */
793static int aztUpdateToc(void)
794{
795 int st;
796
797#ifdef AZT_DEBUG
798 printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies);
799#endif
800 if (aztTocUpToDate)
801 return 0;
802
803 if (aztGetDiskInfo() < 0)
804 return -EIO;
805
806 if (aztGetToc(0) < 0)
807 return -EIO;
808
809 /*audio disk detection
810 with my Aztech drive there is no audio status bit, so I use the copy
811 protection bit of the first track. If this track is copy protected
812 (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */
813 if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
814 DiskInfo.audio = 1;
815 else
816 DiskInfo.audio = 0;
817
818 /* XA detection */
819 if (!DiskInfo.audio) {
820 azt_Play.start.min = 0; /*XA detection only seems to work */
821 azt_Play.start.sec = 2; /*when we play a track */
822 azt_Play.start.frame = 0;
823 azt_Play.end.min = 0;
824 azt_Play.end.sec = 0;
825 azt_Play.end.frame = 1;
826 if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
827 return -1;
828 DTEN_LOW;
829 for (st = 0; st < CD_FRAMESIZE; st++)
830 inb(DATA_PORT);
831 }
832 DiskInfo.xa = getAztStatus() & AST_MODE;
833 if (DiskInfo.xa) {
834 printk
835 ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
836 }
837
838 /*multisession detection
839 support for multisession CDs is done automatically with Aztech drives,
840 we don't have to take care about TOC redirection; if we want the isofs
841 to take care about redirection, we have to set AZT_MULTISESSION to 1 */
842 DiskInfo.multi = 0;
843#if AZT_MULTISESSION
844 if (DiskInfo.xa) {
845 aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */
846 }
847#endif
848 if (DiskInfo.multi) {
849 DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
850 DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
851 DiskInfo.lastSession.frame =
852 Toc[DiskInfo.next].diskTime.frame;
853 printk("aztcd: Multisession support experimental\n");
854 } else {
855 DiskInfo.lastSession.min =
856 Toc[DiskInfo.first].diskTime.min;
857 DiskInfo.lastSession.sec =
858 Toc[DiskInfo.first].diskTime.sec;
859 DiskInfo.lastSession.frame =
860 Toc[DiskInfo.first].diskTime.frame;
861 }
862
863 aztTocUpToDate = 1;
864#ifdef AZT_DEBUG
865 printk("aztcd: exiting aztUpdateToc Time:%li\n", jiffies);
866#endif
867 return 0;
868}
869
870
871/* Read the table of contents header, i.e. no. of tracks and start of first
872 * track
873 */
874static int aztGetDiskInfo(void)
875{
876 int limit;
877 unsigned char test;
878 struct azt_Toc qInfo;
879
880#ifdef AZT_DEBUG
881 printk("aztcd: starting aztGetDiskInfo Time:%li\n", jiffies);
882#endif
883 if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
884 RETURNM("aztGetDiskInfo 1", -1);
885 STEN_LOW_WAIT;
886 test = 0;
887 for (limit = 300; limit > 0; limit--) {
888 if (aztGetQChannelInfo(&qInfo) < 0)
889 RETURNM("aztGetDiskInfo 2", -1);
890 if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */
891 DiskInfo.first = qInfo.diskTime.min;
892 DiskInfo.first = azt_bcd2bin(DiskInfo.first);
893 test = test | 0x01;
894 }
895 if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
896 DiskInfo.last = qInfo.diskTime.min;
897 DiskInfo.last = azt_bcd2bin(DiskInfo.last);
898 test = test | 0x02;
899 }
900 if (qInfo.pointIndex == 0xA2) { /*DiskLength */
901 DiskInfo.diskLength.min = qInfo.diskTime.min;
902 DiskInfo.diskLength.sec = qInfo.diskTime.sec;
903 DiskInfo.diskLength.frame = qInfo.diskTime.frame;
904 test = test | 0x04;
905 }
906 if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) { /*StartTime of First Track */
907 DiskInfo.firstTrack.min = qInfo.diskTime.min;
908 DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
909 DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
910 test = test | 0x08;
911 }
912 if (test == 0x0F)
913 break;
914 }
915#ifdef AZT_DEBUG
916 printk("aztcd: exiting aztGetDiskInfo Time:%li\n", jiffies);
917 printk
918 ("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n",
919 DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
920 DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
921 DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
922 DiskInfo.firstTrack.frame);
923#endif
924 if (test != 0x0F)
925 return -1;
926 return 0;
927}
928
929#if AZT_MULTISESSION
930/*
931 * Get Multisession Disk Info
932 */
933static int aztGetMultiDiskInfo(void)
934{
935 int limit, k = 5;
936 unsigned char test;
937 struct azt_Toc qInfo;
938
939#ifdef AZT_DEBUG
940 printk("aztcd: starting aztGetMultiDiskInfo\n");
941#endif
942
943 do {
944 azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min;
945 azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec;
946 azt_Play.start.frame =
947 Toc[DiskInfo.last + 1].diskTime.frame;
948 test = 0;
949
950 for (limit = 30; limit > 0; limit--) { /*Seek for LeadIn of next session */
951 if (aztSeek(&azt_Play))
952 RETURNM("aztGetMultiDiskInfo 1", -1);
953 if (aztGetQChannelInfo(&qInfo) < 0)
954 RETURNM("aztGetMultiDiskInfo 2", -1);
955 if ((qInfo.track == 0) && (qInfo.pointIndex))
956 break; /*LeadIn found */
957 if ((azt_Play.start.sec += 10) > 59) {
958 azt_Play.start.sec = 0;
959 azt_Play.start.min++;
960 }
961 }
962 if (!limit)
963 break; /*Check, if a leadin track was found, if not we're
964 at the end of the disk */
965#ifdef AZT_DEBUG_MULTISESSION
966 printk("leadin found track %d pointIndex %x limit %d\n",
967 qInfo.track, qInfo.pointIndex, limit);
968#endif
969 for (limit = 300; limit > 0; limit--) {
970 if (++azt_Play.start.frame > 74) {
971 azt_Play.start.frame = 0;
972 if (azt_Play.start.sec > 59) {
973 azt_Play.start.sec = 0;
974 azt_Play.start.min++;
975 }
976 }
977 if (aztSeek(&azt_Play))
978 RETURNM("aztGetMultiDiskInfo 3", -1);
979 if (aztGetQChannelInfo(&qInfo) < 0)
980 RETURNM("aztGetMultiDiskInfo 4", -1);
981 if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */
982 DiskInfo.next = qInfo.diskTime.min;
983 DiskInfo.next = azt_bcd2bin(DiskInfo.next);
984 test = test | 0x01;
985 }
986 if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
987 DiskInfo.last = qInfo.diskTime.min;
988 DiskInfo.last = azt_bcd2bin(DiskInfo.last);
989 test = test | 0x02;
990 }
991 if (qInfo.pointIndex == 0xA2) { /*DiskLength */
992 DiskInfo.diskLength.min =
993 qInfo.diskTime.min;
994 DiskInfo.diskLength.sec =
995 qInfo.diskTime.sec;
996 DiskInfo.diskLength.frame =
997 qInfo.diskTime.frame;
998 test = test | 0x04;
999 }
1000 if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) { /*StartTime of Next Track */
1001 DiskInfo.nextSession.min =
1002 qInfo.diskTime.min;
1003 DiskInfo.nextSession.sec =
1004 qInfo.diskTime.sec;
1005 DiskInfo.nextSession.frame =
1006 qInfo.diskTime.frame;
1007 test = test | 0x08;
1008 }
1009 if (test == 0x0F)
1010 break;
1011 }
1012#ifdef AZT_DEBUG_MULTISESSION
1013 printk
1014 ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n",
1015 DiskInfo.first, DiskInfo.next, DiskInfo.last,
1016 DiskInfo.diskLength.min, DiskInfo.diskLength.sec,
1017 DiskInfo.diskLength.frame, DiskInfo.firstTrack.min,
1018 DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame,
1019 DiskInfo.nextSession.min, DiskInfo.nextSession.sec,
1020 DiskInfo.nextSession.frame);
1021#endif
1022 if (test != 0x0F)
1023 break;
1024 else
1025 DiskInfo.multi = 1; /*found TOC of more than one session */
1026 aztGetToc(1);
1027 } while (--k);
1028
1029#ifdef AZT_DEBUG
1030 printk("aztcd: exiting aztGetMultiDiskInfo Time:%li\n", jiffies);
1031#endif
1032 return 0;
1033}
1034#endif
1035
1036/*
1037 * Read the table of contents (TOC)
1038 */
1039static int aztGetToc(int multi)
1040{
1041 int i, px;
1042 int limit;
1043 struct azt_Toc qInfo;
1044
1045#ifdef AZT_DEBUG
1046 printk("aztcd: starting aztGetToc Time:%li\n", jiffies);
1047#endif
1048 if (!multi) {
1049 for (i = 0; i < MAX_TRACKS; i++)
1050 Toc[i].pointIndex = 0;
1051 i = DiskInfo.last + 3;
1052 } else {
1053 for (i = DiskInfo.next; i < MAX_TRACKS; i++)
1054 Toc[i].pointIndex = 0;
1055 i = DiskInfo.last + 4 - DiskInfo.next;
1056 }
1057
1058/*Is there a good reason to stop motor before TOC read?
1059 if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
1060 STEN_LOW_WAIT;
1061*/
1062
1063 if (!multi) {
1064 azt_mode = 0x05;
1065 if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
1066 RETURNM("aztGetToc 2", -1);
1067 STEN_LOW_WAIT;
1068 }
1069 for (limit = 300; limit > 0; limit--) {
1070 if (multi) {
1071 if (++azt_Play.start.sec > 59) {
1072 azt_Play.start.sec = 0;
1073 azt_Play.start.min++;
1074 }
1075 if (aztSeek(&azt_Play))
1076 RETURNM("aztGetToc 3", -1);
1077 }
1078 if (aztGetQChannelInfo(&qInfo) < 0)
1079 break;
1080
1081 px = azt_bcd2bin(qInfo.pointIndex);
1082
1083 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1084 if (Toc[px].pointIndex == 0) {
1085 Toc[px] = qInfo;
1086 i--;
1087 }
1088
1089 if (i <= 0)
1090 break;
1091 }
1092
1093 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1094 Toc[DiskInfo.last].trackTime = DiskInfo.diskLength;
1095
1096#ifdef AZT_DEBUG_MULTISESSION
1097 printk("aztcd: exiting aztGetToc\n");
1098 for (i = 1; i <= DiskInfo.last + 1; i++)
1099 printk
1100 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
1101 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1102 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1103 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1104 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1105 for (i = 100; i < 103; i++)
1106 printk
1107 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
1108 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1109 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1110 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1111 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1112#endif
1113
1114 return limit > 0 ? 0 : -1;
1115}
1116
1117
1118/*##########################################################################
1119 Kernel Interface Functions
1120 ##########################################################################
1121*/
1122
1123#ifndef MODULE
1124static int __init aztcd_setup(char *str)
1125{
1126 int ints[4];
1127
1128 (void) get_options(str, ARRAY_SIZE(ints), ints);
1129
1130 if (ints[0] > 0)
1131 azt_port = ints[1];
1132 if (ints[1] > 1)
1133 azt_cont = ints[2];
1134 return 1;
1135}
1136
1137__setup("aztcd=", aztcd_setup);
1138
1139#endif /* !MODULE */
1140
1141/*
1142 * Checking if the media has been changed
1143*/
1144static int check_aztcd_media_change(struct gendisk *disk)
1145{
1146 if (aztDiskChanged) { /* disk changed */
1147 aztDiskChanged = 0;
1148 return 1;
1149 } else
1150 return 0; /* no change */
1151}
1152
1153/*
1154 * Kernel IO-controls
1155*/
1156static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
1157 unsigned long arg)
1158{
1159 int i;
1160 struct azt_Toc qInfo;
1161 struct cdrom_ti ti;
1162 struct cdrom_tochdr tocHdr;
1163 struct cdrom_msf msf;
1164 struct cdrom_tocentry entry;
1165 struct azt_Toc *tocPtr;
1166 struct cdrom_subchnl subchnl;
1167 struct cdrom_volctrl volctrl;
1168 void __user *argp = (void __user *)arg;
1169
1170#ifdef AZT_DEBUG
1171 printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n",
1172 cmd, jiffies);
1173 printk("aztcd Status %x\n", getAztStatus());
1174#endif
1175 if (!ip)
1176 RETURNM("aztcd_ioctl 1", -EINVAL);
1177 if (getAztStatus() < 0)
1178 RETURNM("aztcd_ioctl 2", -EIO);
1179 if ((!aztTocUpToDate) || (aztDiskChanged)) {
1180 if ((i = aztUpdateToc()) < 0)
1181 RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
1182 }
1183
1184 switch (cmd) {
1185 case CDROMSTART: /* Spin up the drive. Don't know, what to do,
1186 at least close the tray */
1187#if AZT_PRIVATE_IOCTLS
1188 if (aztSendCmd(ACMD_CLOSE))
1189 RETURNM("aztcd_ioctl 4", -1);
1190 STEN_LOW_WAIT;
1191#endif
1192 break;
1193 case CDROMSTOP: /* Spin down the drive */
1194 if (aztSendCmd(ACMD_STOP))
1195 RETURNM("aztcd_ioctl 5", -1);
1196 STEN_LOW_WAIT;
1197 /* should we do anything if it fails? */
1198 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1199 break;
1200 case CDROMPAUSE: /* Pause the drive */
1201 if (aztAudioStatus != CDROM_AUDIO_PLAY)
1202 return -EINVAL;
1203
1204 if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */
1205 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1206 RETURNM("aztcd_ioctl 7", 0);
1207 }
1208 azt_Play.start = qInfo.diskTime; /* remember restart point */
1209
1210 if (aztSendCmd(ACMD_PAUSE))
1211 RETURNM("aztcd_ioctl 8", -1);
1212 STEN_LOW_WAIT;
1213 aztAudioStatus = CDROM_AUDIO_PAUSED;
1214 break;
1215 case CDROMRESUME: /* Play it again, Sam */
1216 if (aztAudioStatus != CDROM_AUDIO_PAUSED)
1217 return -EINVAL;
1218 /* restart the drive at the saved position. */
1219 i = aztPlay(&azt_Play);
1220 if (i < 0) {
1221 aztAudioStatus = CDROM_AUDIO_ERROR;
1222 return -EIO;
1223 }
1224 aztAudioStatus = CDROM_AUDIO_PLAY;
1225 break;
1226 case CDROMMULTISESSION: /*multisession support -- experimental */
1227 {
1228 struct cdrom_multisession ms;
1229#ifdef AZT_DEBUG
1230 printk("aztcd ioctl MULTISESSION\n");
1231#endif
1232 if (copy_from_user(&ms, argp,
1233 sizeof(struct cdrom_multisession)))
1234 return -EFAULT;
1235 if (ms.addr_format == CDROM_MSF) {
1236 ms.addr.msf.minute =
1237 azt_bcd2bin(DiskInfo.lastSession.min);
1238 ms.addr.msf.second =
1239 azt_bcd2bin(DiskInfo.lastSession.sec);
1240 ms.addr.msf.frame =
1241 azt_bcd2bin(DiskInfo.lastSession.
1242 frame);
1243 } else if (ms.addr_format == CDROM_LBA)
1244 ms.addr.lba =
1245 azt_msf2hsg(&DiskInfo.lastSession);
1246 else
1247 return -EINVAL;
1248 ms.xa_flag = DiskInfo.xa;
1249 if (copy_to_user(argp, &ms,
1250 sizeof(struct cdrom_multisession)))
1251 return -EFAULT;
1252#ifdef AZT_DEBUG
1253 if (ms.addr_format == CDROM_MSF)
1254 printk
1255 ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
1256 ms.xa_flag, ms.addr.msf.minute,
1257 ms.addr.msf.second, ms.addr.msf.frame,
1258 DiskInfo.lastSession.min,
1259 DiskInfo.lastSession.sec,
1260 DiskInfo.lastSession.frame);
1261 else
1262 printk
1263 ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
1264 ms.xa_flag, ms.addr.lba,
1265 DiskInfo.lastSession.min,
1266 DiskInfo.lastSession.sec,
1267 DiskInfo.lastSession.frame);
1268#endif
1269 return 0;
1270 }
1271 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
1272 if (copy_from_user(&ti, argp, sizeof ti))
1273 return -EFAULT;
1274 if (ti.cdti_trk0 < DiskInfo.first
1275 || ti.cdti_trk0 > DiskInfo.last
1276 || ti.cdti_trk1 < ti.cdti_trk0) {
1277 return -EINVAL;
1278 }
1279 if (ti.cdti_trk1 > DiskInfo.last)
1280 ti.cdti_trk1 = DiskInfo.last;
1281 azt_Play.start = Toc[ti.cdti_trk0].diskTime;
1282 azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
1283#ifdef AZT_DEBUG
1284 printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
1285 azt_Play.start.min, azt_Play.start.sec,
1286 azt_Play.start.frame, azt_Play.end.min,
1287 azt_Play.end.sec, azt_Play.end.frame);
1288#endif
1289 i = aztPlay(&azt_Play);
1290 if (i < 0) {
1291 aztAudioStatus = CDROM_AUDIO_ERROR;
1292 return -EIO;
1293 }
1294 aztAudioStatus = CDROM_AUDIO_PLAY;
1295 break;
1296 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
1297/* if (aztAudioStatus == CDROM_AUDIO_PLAY)
1298 { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
1299 STEN_LOW;
1300 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1301 }
1302*/
1303 if (copy_from_user(&msf, argp, sizeof msf))
1304 return -EFAULT;
1305 /* convert to bcd */
1306 azt_bin2bcd(&msf.cdmsf_min0);
1307 azt_bin2bcd(&msf.cdmsf_sec0);
1308 azt_bin2bcd(&msf.cdmsf_frame0);
1309 azt_bin2bcd(&msf.cdmsf_min1);
1310 azt_bin2bcd(&msf.cdmsf_sec1);
1311 azt_bin2bcd(&msf.cdmsf_frame1);
1312 azt_Play.start.min = msf.cdmsf_min0;
1313 azt_Play.start.sec = msf.cdmsf_sec0;
1314 azt_Play.start.frame = msf.cdmsf_frame0;
1315 azt_Play.end.min = msf.cdmsf_min1;
1316 azt_Play.end.sec = msf.cdmsf_sec1;
1317 azt_Play.end.frame = msf.cdmsf_frame1;
1318#ifdef AZT_DEBUG
1319 printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
1320 azt_Play.start.min, azt_Play.start.sec,
1321 azt_Play.start.frame, azt_Play.end.min,
1322 azt_Play.end.sec, azt_Play.end.frame);
1323#endif
1324 i = aztPlay(&azt_Play);
1325 if (i < 0) {
1326 aztAudioStatus = CDROM_AUDIO_ERROR;
1327 return -EIO;
1328 }
1329 aztAudioStatus = CDROM_AUDIO_PLAY;
1330 break;
1331
1332 case CDROMREADTOCHDR: /* Read the table of contents header */
1333 tocHdr.cdth_trk0 = DiskInfo.first;
1334 tocHdr.cdth_trk1 = DiskInfo.last;
1335 if (copy_to_user(argp, &tocHdr, sizeof tocHdr))
1336 return -EFAULT;
1337 break;
1338 case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
1339 if (copy_from_user(&entry, argp, sizeof entry))
1340 return -EFAULT;
1341 if ((!aztTocUpToDate) || aztDiskChanged)
1342 aztUpdateToc();
1343 if (entry.cdte_track == CDROM_LEADOUT)
1344 tocPtr = &Toc[DiskInfo.last + 1];
1345 else if (entry.cdte_track > DiskInfo.last
1346 || entry.cdte_track < DiskInfo.first) {
1347 return -EINVAL;
1348 } else
1349 tocPtr = &Toc[entry.cdte_track];
1350 entry.cdte_adr = tocPtr->ctrl_addr;
1351 entry.cdte_ctrl = tocPtr->ctrl_addr >> 4;
1352 if (entry.cdte_format == CDROM_LBA)
1353 entry.cdte_addr.lba =
1354 azt_msf2hsg(&tocPtr->diskTime);
1355 else if (entry.cdte_format == CDROM_MSF) {
1356 entry.cdte_addr.msf.minute =
1357 azt_bcd2bin(tocPtr->diskTime.min);
1358 entry.cdte_addr.msf.second =
1359 azt_bcd2bin(tocPtr->diskTime.sec);
1360 entry.cdte_addr.msf.frame =
1361 azt_bcd2bin(tocPtr->diskTime.frame);
1362 } else {
1363 return -EINVAL;
1364 }
1365 if (copy_to_user(argp, &entry, sizeof entry))
1366 return -EFAULT;
1367 break;
1368 case CDROMSUBCHNL: /* Get subchannel info */
1369 if (copy_from_user
1370 (&subchnl, argp, sizeof(struct cdrom_subchnl)))
1371 return -EFAULT;
1372 if (aztGetQChannelInfo(&qInfo) < 0) {
1373#ifdef AZT_DEBUG
1374 printk
1375 ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",
1376 cmd);
1377#endif
1378 return -EIO;
1379 }
1380 subchnl.cdsc_audiostatus = aztAudioStatus;
1381 subchnl.cdsc_adr = qInfo.ctrl_addr;
1382 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
1383 subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
1384 subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
1385 if (subchnl.cdsc_format == CDROM_LBA) {
1386 subchnl.cdsc_absaddr.lba =
1387 azt_msf2hsg(&qInfo.diskTime);
1388 subchnl.cdsc_reladdr.lba =
1389 azt_msf2hsg(&qInfo.trackTime);
1390 } else { /*default */
1391 subchnl.cdsc_format = CDROM_MSF;
1392 subchnl.cdsc_absaddr.msf.minute =
1393 azt_bcd2bin(qInfo.diskTime.min);
1394 subchnl.cdsc_absaddr.msf.second =
1395 azt_bcd2bin(qInfo.diskTime.sec);
1396 subchnl.cdsc_absaddr.msf.frame =
1397 azt_bcd2bin(qInfo.diskTime.frame);
1398 subchnl.cdsc_reladdr.msf.minute =
1399 azt_bcd2bin(qInfo.trackTime.min);
1400 subchnl.cdsc_reladdr.msf.second =
1401 azt_bcd2bin(qInfo.trackTime.sec);
1402 subchnl.cdsc_reladdr.msf.frame =
1403 azt_bcd2bin(qInfo.trackTime.frame);
1404 }
1405 if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl)))
1406 return -EFAULT;
1407 break;
1408 case CDROMVOLCTRL: /* Volume control
1409 * With my Aztech CD268-01A volume control does not work, I can only
1410 turn the channels on (any value !=0) or off (value==0). Maybe it
1411 works better with your drive */
1412 if (copy_from_user(&volctrl, argp, sizeof(volctrl)))
1413 return -EFAULT;
1414 azt_Play.start.min = 0x21;
1415 azt_Play.start.sec = 0x84;
1416 azt_Play.start.frame = volctrl.channel0;
1417 azt_Play.end.min = volctrl.channel1;
1418 azt_Play.end.sec = volctrl.channel2;
1419 azt_Play.end.frame = volctrl.channel3;
1420 sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
1421 STEN_LOW_WAIT;
1422 break;
1423 case CDROMEJECT:
1424 aztUnlockDoor(); /* Assume user knows what they're doing */
1425 /* all drives can at least stop! */
1426 if (aztAudioStatus == CDROM_AUDIO_PLAY) {
1427 if (aztSendCmd(ACMD_STOP))
1428 RETURNM("azt_ioctl 10", -1);
1429 STEN_LOW_WAIT;
1430 }
1431 if (aztSendCmd(ACMD_EJECT))
1432 RETURNM("azt_ioctl 11", -1);
1433 STEN_LOW_WAIT;
1434 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
1435 break;
1436 case CDROMEJECT_SW:
1437 azt_auto_eject = (char) arg;
1438 break;
1439 case CDROMRESET:
1440 outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */
1441 STEN_LOW;
1442 if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */
1443 printk
1444 ("aztcd: AZTECH CD-ROM drive does not respond\n");
1445 }
1446 break;
1447/*Take care, the following code is not compatible with other CD-ROM drivers,
1448 use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
1449 if you do not want to use it!
1450*/
1451#if AZT_PRIVATE_IOCTLS
1452 case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */
1453 case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */
1454 {
1455 if (copy_from_user(&msf, argp, sizeof msf))
1456 return -EFAULT;
1457 /* convert to bcd */
1458 azt_bin2bcd(&msf.cdmsf_min0);
1459 azt_bin2bcd(&msf.cdmsf_sec0);
1460 azt_bin2bcd(&msf.cdmsf_frame0);
1461 msf.cdmsf_min1 = 0;
1462 msf.cdmsf_sec1 = 0;
1463 msf.cdmsf_frame1 = 1; /*read only one frame */
1464 azt_Play.start.min = msf.cdmsf_min0;
1465 azt_Play.start.sec = msf.cdmsf_sec0;
1466 azt_Play.start.frame = msf.cdmsf_frame0;
1467 azt_Play.end.min = msf.cdmsf_min1;
1468 azt_Play.end.sec = msf.cdmsf_sec1;
1469 azt_Play.end.frame = msf.cdmsf_frame1;
1470 if (cmd == CDROMREADRAW) {
1471 if (DiskInfo.xa) {
1472 return -1; /*XA Disks can't be read raw */
1473 } else {
1474 if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play))
1475 return -1;
1476 DTEN_LOW;
1477 insb(DATA_PORT, buf, CD_FRAMESIZE_RAW);
1478 if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW))
1479 return -EFAULT;
1480 }
1481 } else
1482 /*CDROMREADCOOKED*/ {
1483 if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
1484 return -1;
1485 DTEN_LOW;
1486 insb(DATA_PORT, buf, CD_FRAMESIZE);
1487 if (copy_to_user(argp, &buf, CD_FRAMESIZE))
1488 return -EFAULT;
1489 }
1490 }
1491 break;
1492 case CDROMSEEK: /*seek msf address */
1493 if (copy_from_user(&msf, argp, sizeof msf))
1494 return -EFAULT;
1495 /* convert to bcd */
1496 azt_bin2bcd(&msf.cdmsf_min0);
1497 azt_bin2bcd(&msf.cdmsf_sec0);
1498 azt_bin2bcd(&msf.cdmsf_frame0);
1499 azt_Play.start.min = msf.cdmsf_min0;
1500 azt_Play.start.sec = msf.cdmsf_sec0;
1501 azt_Play.start.frame = msf.cdmsf_frame0;
1502 if (aztSeek(&azt_Play))
1503 return -1;
1504 break;
1505#endif /*end of incompatible code */
1506 case CDROMREADMODE1: /*set read data in mode 1 */
1507 return aztSetDiskType(AZT_MODE_1);
1508 case CDROMREADMODE2: /*set read data in mode 2 */
1509 return aztSetDiskType(AZT_MODE_2);
1510 default:
1511 return -EINVAL;
1512 }
1513#ifdef AZT_DEBUG
1514 printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n", cmd,
1515 jiffies);
1516#endif
1517 return 0;
1518}
1519
1520/*
1521 * Take care of the different block sizes between cdrom and Linux.
1522 * When Linux gets variable block sizes this will probably go away.
1523 */
1524static void azt_transfer(void)
1525{
1526#ifdef AZT_TEST
1527 printk("aztcd: executing azt_transfer Time:%li\n", jiffies);
1528#endif
1529 if (!current_valid())
1530 return;
1531
1532 while (CURRENT->nr_sectors) {
1533 int bn = CURRENT->sector / 4;
1534 int i;
1535 for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i);
1536 if (i < AZT_BUF_SIZ) {
1537 int offs = (i * 4 + (CURRENT->sector & 3)) * 512;
1538 int nr_sectors = 4 - (CURRENT->sector & 3);
1539 if (azt_buf_out != i) {
1540 azt_buf_out = i;
1541 if (azt_buf_bn[i] != bn) {
1542 azt_buf_out = -1;
1543 continue;
1544 }
1545 }
1546 if (nr_sectors > CURRENT->nr_sectors)
1547 nr_sectors = CURRENT->nr_sectors;
1548 memcpy(CURRENT->buffer, azt_buf + offs,
1549 nr_sectors * 512);
1550 CURRENT->nr_sectors -= nr_sectors;
1551 CURRENT->sector += nr_sectors;
1552 CURRENT->buffer += nr_sectors * 512;
1553 } else {
1554 azt_buf_out = -1;
1555 break;
1556 }
1557 }
1558}
1559
1560static void do_aztcd_request(request_queue_t * q)
1561{
1562#ifdef AZT_TEST
1563 printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector,
1564 CURRENT->nr_sectors, jiffies);
1565#endif
1566 if (DiskInfo.audio) {
1567 printk("aztcd: Error, tried to mount an Audio CD\n");
1568 end_request(CURRENT, 0);
1569 return;
1570 }
1571 azt_transfer_is_active = 1;
1572 while (current_valid()) {
1573 azt_transfer();
1574 if (CURRENT->nr_sectors == 0) {
1575 end_request(CURRENT, 1);
1576 } else {
1577 azt_buf_out = -1; /* Want to read a block not in buffer */
1578 if (azt_state == AZT_S_IDLE) {
1579 if ((!aztTocUpToDate) || aztDiskChanged) {
1580 if (aztUpdateToc() < 0) {
1581 while (current_valid())
1582 end_request(CURRENT, 0);
1583 break;
1584 }
1585 }
1586 azt_state = AZT_S_START;
1587 AztTries = 5;
1588 SET_TIMER(azt_poll, HZ / 100);
1589 }
1590 break;
1591 }
1592 }
1593 azt_transfer_is_active = 0;
1594#ifdef AZT_TEST2
1595 printk
1596 ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n",
1597 azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
1598 printk(" do_aztcd_request ends Time:%li\n", jiffies);
1599#endif
1600}
1601
1602
1603static void azt_invalidate_buffers(void)
1604{
1605 int i;
1606
1607#ifdef AZT_DEBUG
1608 printk("aztcd: executing azt_invalidate_buffers\n");
1609#endif
1610 for (i = 0; i < AZT_BUF_SIZ; ++i)
1611 azt_buf_bn[i] = -1;
1612 azt_buf_out = -1;
1613}
1614
1615/*
1616 * Open the device special file. Check that a disk is in.
1617 */
1618static int aztcd_open(struct inode *ip, struct file *fp)
1619{
1620 int st;
1621
1622#ifdef AZT_DEBUG
1623 printk("aztcd: starting aztcd_open\n");
1624#endif
1625
1626 if (aztPresent == 0)
1627 return -ENXIO; /* no hardware */
1628
1629 if (!azt_open_count && azt_state == AZT_S_IDLE) {
1630 azt_invalidate_buffers();
1631
1632 st = getAztStatus(); /* check drive status */
1633 if (st == -1)
1634 goto err_out; /* drive doesn't respond */
1635
1636 if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */
1637 printk("aztcd: Door Open?\n");
1638 aztCloseDoor();
1639 st = getAztStatus();
1640 }
1641
1642 if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) { /*no disk in drive or changed */
1643 printk
1644 ("aztcd: Disk Changed or No Disk in Drive?\n");
1645 aztTocUpToDate = 0;
1646 }
1647 if (aztUpdateToc())
1648 goto err_out;
1649
1650 }
1651 ++azt_open_count;
1652 aztLockDoor();
1653
1654#ifdef AZT_DEBUG
1655 printk("aztcd: exiting aztcd_open\n");
1656#endif
1657 return 0;
1658
1659 err_out:
1660 return -EIO;
1661}
1662
1663
1664/*
1665 * On close, we flush all azt blocks from the buffer cache.
1666 */
1667static int aztcd_release(struct inode *inode, struct file *file)
1668{
1669#ifdef AZT_DEBUG
1670 printk("aztcd: executing aztcd_release\n");
1671 printk("inode: %p, device: %s file: %p\n", inode,
1672 inode->i_bdev->bd_disk->disk_name, file);
1673#endif
1674 if (!--azt_open_count) {
1675 azt_invalidate_buffers();
1676 aztUnlockDoor();
1677 if (azt_auto_eject)
1678 aztSendCmd(ACMD_EJECT);
1679 CLEAR_TIMER;
1680 }
1681 return 0;
1682}
1683
1684static struct gendisk *azt_disk;
1685
1686/*
1687 * Test for presence of drive and initialize it. Called at boot time.
1688 */
1689
1690static int __init aztcd_init(void)
1691{
1692 long int count, max_count;
1693 unsigned char result[50];
1694 int st;
1695 void* status = NULL;
1696 int i = 0;
1697 int ret = 0;
1698
1699 if (azt_port == 0) {
1700 printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization");
1701 return -EIO;
1702 }
1703
1704 printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM "
1705 "CD-ROM Driver\n");
1706 printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n");
1707 if (azt_port == -1) {
1708 printk
1709 ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n",
1710 AZT_VERSION);
1711 } else
1712 printk
1713 ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n",
1714 AZT_VERSION, azt_port);
1715 printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/"
1716 "Documentation/cdrom/aztcd\n");
1717
1718
1719#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */
1720 if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) {
1721 printk
1722 ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
1723 AZT_SW32_BASE_ADDR, AZT_SW32_INIT,
1724 AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG);
1725 return -EIO;
1726 } else {
1727 printk(KERN_INFO
1728 "aztcd: Soundwave32 card detected at %x Version %x\n",
1729 AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
1730 outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG);
1731 for (count = 0; count < 10000; count++); /*delay a bit */
1732 }
1733#endif
1734
1735 /* check for presence of drive */
1736
1737 if (azt_port == -1) { /* autoprobing for proprietary interface */
1738 for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) {
1739 azt_port = azt_port_auto[i];
1740 printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x"
1741 "\n", azt_port);
1742 /*proprietary interfaces need 4 bytes */
1743 if (!request_region(azt_port, 4, "aztcd")) {
1744 continue;
1745 }
1746 outb(POLLED, MODE_PORT);
1747 inb(CMD_PORT);
1748 inb(CMD_PORT);
1749 outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
1750
1751 aztTimeOutCount = 0;
1752 do {
1753 aztIndatum = inb(STATUS_PORT);
1754 aztTimeOutCount++;
1755 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1756 break;
1757 } while (aztIndatum & AFL_STATUS);
1758 if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */
1759 break;
1760 }
1761 else { /* Drive not found on this port - try next one */
1762 release_region(azt_port, 4);
1763 }
1764 }
d93c2efc 1765 if ((i == 16) || (azt_port_auto[i] == 0)) {
1da177e4
LT
1766 printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n");
1767 return -EIO;
1768 }
1769 } else { /* no autoprobing */
1770 if ((azt_port == 0x1f0) || (azt_port == 0x170))
1771 status = request_region(azt_port, 8, "aztcd"); /*IDE-interfaces need 8 bytes */
1772 else
1773 status = request_region(azt_port, 4, "aztcd"); /*proprietary interfaces need 4 bytes */
1774 if (!status) {
1775 printk(KERN_WARNING "aztcd: conflict, I/O port (%X) "
1776 "already used\n", azt_port);
1777 return -EIO;
1778 }
1779
1780 if ((azt_port == 0x1f0) || (azt_port == 0x170))
1781 SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
1782
1783 outb(POLLED, MODE_PORT);
1784 inb(CMD_PORT);
1785 inb(CMD_PORT);
1786 outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
1787
1788 aztTimeOutCount = 0;
1789 do {
1790 aztIndatum = inb(STATUS_PORT);
1791 aztTimeOutCount++;
1792 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1793 break;
1794 } while (aztIndatum & AFL_STATUS);
1795
1796 if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */
1797#ifndef MODULE
1798 if (azt_cont != 0x79) {
1799 printk(KERN_WARNING "aztcd: no AZTECH CD-ROM "
1800 "drive found-Try boot parameter aztcd="
1801 "<BaseAddress>,0x79\n");
1802 ret = -EIO;
1803 goto err_out;
1804 }
1805#else
1806 if (0) {
1807 }
1808#endif
1809 else {
1810 printk(KERN_INFO "aztcd: drive reset - "
1811 "please wait\n");
1812 for (count = 0; count < 50; count++) {
1813 inb(STATUS_PORT); /*removing all data from earlier tries */
1814 inb(DATA_PORT);
1815 }
1816 outb(POLLED, MODE_PORT);
1817 inb(CMD_PORT);
1818 inb(CMD_PORT);
1819 getAztStatus(); /*trap errors */
1820 outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */
1821 STEN_LOW;
1822 if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */
1823 printk(KERN_WARNING "aztcd: no AZTECH "
1824 "CD-ROM drive found\n");
1825 ret = -EIO;
1826 goto err_out;
1827 }
1828
1829 for (count = 0; count < AZT_TIMEOUT;
1830 count++)
1831 barrier(); /* Stop gcc 2.96 being smart */
1832 /* use udelay(), damnit -- AV */
1833
1834 if ((st = getAztStatus()) == -1) {
1835 printk(KERN_WARNING "aztcd: Drive Status"
1836 " Error Status=%x\n", st);
1837 ret = -EIO;
1838 goto err_out;
1839 }
1840#ifdef AZT_DEBUG
1841 printk(KERN_DEBUG "aztcd: Status = %x\n", st);
1842#endif
1843 outb(POLLED, MODE_PORT);
1844 inb(CMD_PORT);
1845 inb(CMD_PORT);
1846 outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */
1847 STEN_LOW;
1848 OP_OK;
1849 }
1850 }
1851 }
1852
1853 azt_init_end = 1;
1854 STEN_LOW;
1855 result[0] = inb(DATA_PORT); /*reading in a null byte??? */
1856 for (count = 1; count < 50; count++) { /*Reading version string */
1857 aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */
1858 do {
1859 aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */
1860 aztTimeOutCount++;
1861 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1862 break;
1863 } while (aztIndatum & AFL_STATUS);
1864 if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
1865 break; /*all chars read? */
1866 result[count] = inb(DATA_PORT);
1867 }
1868 if (count > 30)
1869 max_count = 30; /*print max.30 chars of the version string */
1870 else
1871 max_count = count;
1872 printk(KERN_INFO "aztcd: FirmwareVersion=");
1873 for (count = 1; count < max_count; count++)
1874 printk("%c", result[count]);
1875 printk("<<>> ");
1876
1877 if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) {
1878 printk("AZTECH drive detected\n");
1879 /*AZTECH*/}
1880 else if ((result[2] == 'C') && (result[3] == 'D')
1881 && (result[4] == 'D')) {
1882 printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */
1883 } else if ((result[1] == 0x03) && (result[2] == '5')) {
1884 printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */
1885 } else { /*OTHERS or none */
1886 printk("\nunknown drive or firmware version detected\n");
1887 printk
1888 ("aztcd may not run stable, if you want to try anyhow,\n");
1889 printk("boot with: aztcd=<BaseAddress>,0x79\n");
1890 if ((azt_cont != 0x79)) {
1891 printk("aztcd: FirmwareVersion=");
1892 for (count = 1; count < 5; count++)
1893 printk("%c", result[count]);
1894 printk("<<>> ");
1895 printk("Aborted\n");
1896 ret = -EIO;
1897 goto err_out;
1898 }
1899 }
1900 azt_disk = alloc_disk(1);
1901 if (!azt_disk)
1902 goto err_out;
1903
1904 if (register_blkdev(MAJOR_NR, "aztcd")) {
1905 ret = -EIO;
1906 goto err_out2;
1907 }
1908
1909 azt_queue = blk_init_queue(do_aztcd_request, &aztSpin);
1910 if (!azt_queue) {
1911 ret = -ENOMEM;
1912 goto err_out3;
1913 }
1914
1915 blk_queue_hardsect_size(azt_queue, 2048);
1916 azt_disk->major = MAJOR_NR;
1917 azt_disk->first_minor = 0;
1918 azt_disk->fops = &azt_fops;
1919 sprintf(azt_disk->disk_name, "aztcd");
1da177e4
LT
1920 azt_disk->queue = azt_queue;
1921 add_disk(azt_disk);
1922 azt_invalidate_buffers();
1923 aztPresent = 1;
1924 aztCloseDoor();
1925 return 0;
1926err_out3:
1927 unregister_blkdev(MAJOR_NR, "aztcd");
1928err_out2:
1929 put_disk(azt_disk);
1930err_out:
1931 if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
1932 SWITCH_IDE_MASTER;
1933 release_region(azt_port, 8); /*IDE-interface */
1934 } else
1935 release_region(azt_port, 4); /*proprietary interface */
1936 return ret;
1937
1938}
1939
1940static void __exit aztcd_exit(void)
1941{
1942 del_gendisk(azt_disk);
1943 put_disk(azt_disk);
1944 if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) {
1945 printk("What's that: can't unregister aztcd\n");
1946 return;
1947 }
1948 blk_cleanup_queue(azt_queue);
1949 if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
1950 SWITCH_IDE_MASTER;
1951 release_region(azt_port, 8); /*IDE-interface */
1952 } else
1953 release_region(azt_port, 4); /*proprietary interface */
1954 printk(KERN_INFO "aztcd module released.\n");
1955}
1956
1957module_init(aztcd_init);
1958module_exit(aztcd_exit);
1959
1960/*##########################################################################
1961 Aztcd State Machine: Controls Drive Operating State
1962 ##########################################################################
1963*/
1964static void azt_poll(void)
1965{
1966 int st = 0;
1967 int loop_ctl = 1;
1968 int skip = 0;
1969
1970 if (azt_error) {
1971 if (aztSendCmd(ACMD_GET_ERROR))
1972 RETURN("azt_poll 1");
1973 STEN_LOW;
1974 azt_error = inb(DATA_PORT) & 0xFF;
1975 printk("aztcd: I/O error 0x%02x\n", azt_error);
1976 azt_invalidate_buffers();
1977#ifdef WARN_IF_READ_FAILURE
1978 if (AztTries == 5)
1979 printk
1980 ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n",
1981 azt_next_bn);
1982#endif
1983 if (!AztTries--) {
1984 printk
1985 ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n",
1986 azt_next_bn);
1987 if (azt_transfer_is_active) {
1988 AztTries = 0;
1989 loop_ctl = 0;
1990 }
1991 if (current_valid())
1992 end_request(CURRENT, 0);
1993 AztTries = 5;
1994 }
1995 azt_error = 0;
1996 azt_state = AZT_S_STOP;
1997 }
1998
1999 while (loop_ctl) {
2000 loop_ctl = 0; /* each case must flip this back to 1 if we want
2001 to come back up here */
2002 switch (azt_state) {
2003
2004 case AZT_S_IDLE:
2005#ifdef AZT_TEST3
2006 if (azt_state != azt_state_old) {
2007 azt_state_old = azt_state;
2008 printk("AZT_S_IDLE\n");
2009 }
2010#endif
2011 return;
2012
2013 case AZT_S_START:
2014#ifdef AZT_TEST3
2015 if (azt_state != azt_state_old) {
2016 azt_state_old = azt_state;
2017 printk("AZT_S_START\n");
2018 }
2019#endif
2020 if (aztSendCmd(ACMD_GET_STATUS))
2021 RETURN("azt_poll 2"); /*result will be checked by aztStatus() */
2022 azt_state =
2023 azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
2024 AztTimeout = 3000;
2025 break;
2026
2027 case AZT_S_MODE:
2028#ifdef AZT_TEST3
2029 if (azt_state != azt_state_old) {
2030 azt_state_old = azt_state;
2031 printk("AZT_S_MODE\n");
2032 }
2033#endif
2034 if (!skip) {
2035 if ((st = aztStatus()) != -1) {
2036 if ((st & AST_DSK_CHG)
2037 || (st & AST_NOT_READY)) {
2038 aztDiskChanged = 1;
2039 aztTocUpToDate = 0;
2040 azt_invalidate_buffers();
2041 end_request(CURRENT, 0);
2042 printk
2043 ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
2044 }
2045 } else
2046 break;
2047 }
2048 skip = 0;
2049
2050 if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
2051 aztDiskChanged = 1;
2052 aztTocUpToDate = 0;
2053 printk
2054 ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
2055 end_request(CURRENT, 0);
2056 printk((st & AST_DOOR_OPEN) ?
2057 "aztcd: door open\n" :
2058 "aztcd: disk removed\n");
2059 if (azt_transfer_is_active) {
2060 azt_state = AZT_S_START;
2061 loop_ctl = 1; /* goto immediately */
2062 break;
2063 }
2064 azt_state = AZT_S_IDLE;
2065 while (current_valid())
2066 end_request(CURRENT, 0);
2067 return;
2068 }
2069
2070/* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
2071 outb(0x01, DATA_PORT);
2072 PA_OK;
2073 STEN_LOW;
2074*/
2075 if (aztSendCmd(ACMD_GET_STATUS))
2076 RETURN("azt_poll 4");
2077 STEN_LOW;
2078 azt_mode = 1;
2079 azt_state = AZT_S_READ;
2080 AztTimeout = 3000;
2081
2082 break;
2083
2084
2085 case AZT_S_READ:
2086#ifdef AZT_TEST3
2087 if (azt_state != azt_state_old) {
2088 azt_state_old = azt_state;
2089 printk("AZT_S_READ\n");
2090 }
2091#endif
2092 if (!skip) {
2093 if ((st = aztStatus()) != -1) {
2094 if ((st & AST_DSK_CHG)
2095 || (st & AST_NOT_READY)) {
2096 aztDiskChanged = 1;
2097 aztTocUpToDate = 0;
2098 azt_invalidate_buffers();
2099 printk
2100 ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
2101 end_request(CURRENT, 0);
2102 }
2103 } else
2104 break;
2105 }
2106
2107 skip = 0;
2108 if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
2109 aztDiskChanged = 1;
2110 aztTocUpToDate = 0;
2111 printk((st & AST_DOOR_OPEN) ?
2112 "aztcd: door open\n" :
2113 "aztcd: disk removed\n");
2114 if (azt_transfer_is_active) {
2115 azt_state = AZT_S_START;
2116 loop_ctl = 1;
2117 break;
2118 }
2119 azt_state = AZT_S_IDLE;
2120 while (current_valid())
2121 end_request(CURRENT, 0);
2122 return;
2123 }
2124
2125 if (current_valid()) {
2126 struct azt_Play_msf msf;
2127 int i;
2128 azt_next_bn = CURRENT->sector / 4;
2129 azt_hsg2msf(azt_next_bn, &msf.start);
2130 i = 0;
2131 /* find out in which track we are */
2132 while (azt_msf2hsg(&msf.start) >
2133 azt_msf2hsg(&Toc[++i].trackTime)) {
2134 };
2135 if (azt_msf2hsg(&msf.start) <
2136 azt_msf2hsg(&Toc[i].trackTime) -
2137 AZT_BUF_SIZ) {
2138 azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */
2139 /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */
2140 } else /* don't read beyond end of track */
2141#if AZT_MULTISESSION
2142 {
2143 azt_read_count =
2144 (azt_msf2hsg(&Toc[i].trackTime)
2145 / 4) * 4 -
2146 azt_msf2hsg(&msf.start);
2147 if (azt_read_count < 0)
2148 azt_read_count = 0;
2149 if (azt_read_count > AZT_BUF_SIZ)
2150 azt_read_count =
2151 AZT_BUF_SIZ;
2152 printk
2153 ("aztcd: warning - trying to read beyond end of track\n");
2154/* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
2155*/ }
2156#else
2157 {
2158 azt_read_count = AZT_BUF_SIZ;
2159 }
2160#endif
2161 msf.end.min = 0;
2162 msf.end.sec = 0;
2163 msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */
2164#ifdef AZT_TEST3
2165 printk
2166 ("---reading msf-address %x:%x:%x %x:%x:%x\n",
2167 msf.start.min, msf.start.sec,
2168 msf.start.frame, msf.end.min,
2169 msf.end.sec, msf.end.frame);
2170 printk
2171 ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n",
2172 azt_next_bn, azt_buf_in, azt_buf_out,
2173 azt_buf_bn[azt_buf_in]);
2174#endif
2175 if (azt_read_mode == AZT_MODE_2) {
2176 sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */
2177 } else {
2178 sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */
2179 }
2180 azt_state = AZT_S_DATA;
2181 AztTimeout = READ_TIMEOUT;
2182 } else {
2183 azt_state = AZT_S_STOP;
2184 loop_ctl = 1;
2185 break;
2186 }
2187
2188 break;
2189
2190
2191 case AZT_S_DATA:
2192#ifdef AZT_TEST3
2193 if (azt_state != azt_state_old) {
2194 azt_state_old = azt_state;
2195 printk("AZT_S_DATA\n");
2196 }
2197#endif
2198
2199 st = inb(STATUS_PORT) & AFL_STATUSorDATA;
2200
2201 switch (st) {
2202
2203 case AFL_DATA:
2204#ifdef AZT_TEST3
2205 if (st != azt_st_old) {
2206 azt_st_old = st;
2207 printk("---AFL_DATA st:%x\n", st);
2208 }
2209#endif
2210 if (!AztTries--) {
2211 printk
2212 ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n",
2213 azt_next_bn);
2214 if (azt_transfer_is_active) {
2215 AztTries = 0;
2216 break;
2217 }
2218 if (current_valid())
2219 end_request(CURRENT, 0);
2220 AztTries = 5;
2221 }
2222 azt_state = AZT_S_START;
2223 AztTimeout = READ_TIMEOUT;
2224 loop_ctl = 1;
2225 break;
2226
2227 case AFL_STATUSorDATA:
2228#ifdef AZT_TEST3
2229 if (st != azt_st_old) {
2230 azt_st_old = st;
2231 printk
2232 ("---AFL_STATUSorDATA st:%x\n",
2233 st);
2234 }
2235#endif
2236 break;
2237
2238 default:
2239#ifdef AZT_TEST3
2240 if (st != azt_st_old) {
2241 azt_st_old = st;
2242 printk("---default: st:%x\n", st);
2243 }
2244#endif
2245 AztTries = 5;
2246 if (!current_valid() && azt_buf_in == azt_buf_out) {
2247 azt_state = AZT_S_STOP;
2248 loop_ctl = 1;
2249 break;
2250 }
2251 if (azt_read_count <= 0)
2252 printk
2253 ("aztcd: warning - try to read 0 frames\n");
2254 while (azt_read_count) { /*??? fast read ahead loop */
2255 azt_buf_bn[azt_buf_in] = -1;
2256 DTEN_LOW; /*??? unsolved problem, very
2257 seldom we get timeouts
2258 here, don't now the real
2259 reason. With my drive this
2260 sometimes also happens with
2261 Aztech's original driver under
2262 DOS. Is it a hardware bug?
2263 I tried to recover from such
2264 situations here. Zimmermann */
2265 if (aztTimeOutCount >= AZT_TIMEOUT) {
2266 printk
2267 ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n",
2268 azt_read_count,
2269 CURRENT->nr_sectors,
2270 azt_buf_in);
2271 printk
2272 ("azt_transfer_is_active:%x\n",
2273 azt_transfer_is_active);
2274 azt_read_count = 0;
2275 azt_state = AZT_S_STOP;
2276 loop_ctl = 1;
2277 end_request(CURRENT, 1); /*should we have here (1) or (0)? */
2278 } else {
2279 if (azt_read_mode ==
2280 AZT_MODE_2) {
2281 insb(DATA_PORT,
2282 azt_buf +
2283 CD_FRAMESIZE_RAW
2284 * azt_buf_in,
2285 CD_FRAMESIZE_RAW);
2286 } else {
2287 insb(DATA_PORT,
2288 azt_buf +
2289 CD_FRAMESIZE *
2290 azt_buf_in,
2291 CD_FRAMESIZE);
2292 }
2293 azt_read_count--;
2294#ifdef AZT_TEST3
2295 printk
2296 ("AZT_S_DATA; ---I've read data- read_count: %d\n",
2297 azt_read_count);
2298 printk
2299 ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n",
2300 azt_next_bn,
2301 azt_buf_in,
2302 azt_buf_out,
2303 azt_buf_bn
2304 [azt_buf_in]);
2305#endif
2306 azt_buf_bn[azt_buf_in] =
2307 azt_next_bn++;
2308 if (azt_buf_out == -1)
2309 azt_buf_out =
2310 azt_buf_in;
2311 azt_buf_in =
2312 azt_buf_in + 1 ==
2313 AZT_BUF_SIZ ? 0 :
2314 azt_buf_in + 1;
2315 }
2316 }
2317 if (!azt_transfer_is_active) {
2318 while (current_valid()) {
2319 azt_transfer();
2320 if (CURRENT->nr_sectors ==
2321 0)
2322 end_request(CURRENT, 1);
2323 else
2324 break;
2325 }
2326 }
2327
2328 if (current_valid()
2329 && (CURRENT->sector / 4 < azt_next_bn
2330 || CURRENT->sector / 4 >
2331 azt_next_bn + AZT_BUF_SIZ)) {
2332 azt_state = AZT_S_STOP;
2333 loop_ctl = 1;
2334 break;
2335 }
2336 AztTimeout = READ_TIMEOUT;
2337 if (azt_read_count == 0) {
2338 azt_state = AZT_S_STOP;
2339 loop_ctl = 1;
2340 break;
2341 }
2342 break;
2343 }
2344 break;
2345
2346
2347 case AZT_S_STOP:
2348#ifdef AZT_TEST3
2349 if (azt_state != azt_state_old) {
2350 azt_state_old = azt_state;
2351 printk("AZT_S_STOP\n");
2352 }
2353#endif
2354 if (azt_read_count != 0)
2355 printk("aztcd: discard data=%x frames\n",
2356 azt_read_count);
2357 while (azt_read_count != 0) {
2358 int i;
2359 if (!(inb(STATUS_PORT) & AFL_DATA)) {
2360 if (azt_read_mode == AZT_MODE_2)
2361 for (i = 0;
2362 i < CD_FRAMESIZE_RAW;
2363 i++)
2364 inb(DATA_PORT);
2365 else
2366 for (i = 0;
2367 i < CD_FRAMESIZE; i++)
2368 inb(DATA_PORT);
2369 }
2370 azt_read_count--;
2371 }
2372 if (aztSendCmd(ACMD_GET_STATUS))
2373 RETURN("azt_poll 5");
2374 azt_state = AZT_S_STOPPING;
2375 AztTimeout = 1000;
2376 break;
2377
2378 case AZT_S_STOPPING:
2379#ifdef AZT_TEST3
2380 if (azt_state != azt_state_old) {
2381 azt_state_old = azt_state;
2382 printk("AZT_S_STOPPING\n");
2383 }
2384#endif
2385
2386 if ((st = aztStatus()) == -1 && AztTimeout)
2387 break;
2388
2389 if ((st != -1)
2390 && ((st & AST_DSK_CHG)
2391 || (st & AST_NOT_READY))) {
2392 aztDiskChanged = 1;
2393 aztTocUpToDate = 0;
2394 azt_invalidate_buffers();
2395 printk
2396 ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
2397 end_request(CURRENT, 0);
2398 }
2399
2400#ifdef AZT_TEST3
2401 printk("CURRENT_VALID %d azt_mode %d\n",
2402 current_valid(), azt_mode);
2403#endif
2404
2405 if (current_valid()) {
2406 if (st != -1) {
2407 if (azt_mode == 1) {
2408 azt_state = AZT_S_READ;
2409 loop_ctl = 1;
2410 skip = 1;
2411 break;
2412 } else {
2413 azt_state = AZT_S_MODE;
2414 loop_ctl = 1;
2415 skip = 1;
2416 break;
2417 }
2418 } else {
2419 azt_state = AZT_S_START;
2420 AztTimeout = 1;
2421 }
2422 } else {
2423 azt_state = AZT_S_IDLE;
2424 return;
2425 }
2426 break;
2427
2428 default:
2429 printk("aztcd: invalid state %d\n", azt_state);
2430 return;
2431 } /* case */
2432 } /* while */
2433
2434
2435 if (!AztTimeout--) {
2436 printk("aztcd: timeout in state %d\n", azt_state);
2437 azt_state = AZT_S_STOP;
2438 if (aztSendCmd(ACMD_STOP))
2439 RETURN("azt_poll 6");
2440 STEN_LOW_WAIT;
2441 };
2442
2443 SET_TIMER(azt_poll, HZ / 100);
2444}
2445
2446
2447/*###########################################################################
2448 * Miscellaneous support functions
2449 ###########################################################################
2450*/
2451static void azt_hsg2msf(long hsg, struct msf *msf)
2452{
2453 hsg += 150;
2454 msf->min = hsg / 4500;
2455 hsg %= 4500;
2456 msf->sec = hsg / 75;
2457 msf->frame = hsg % 75;
2458#ifdef AZT_DEBUG
2459 if (msf->min >= 70)
2460 printk("aztcd: Error hsg2msf address Minutes\n");
2461 if (msf->sec >= 60)
2462 printk("aztcd: Error hsg2msf address Seconds\n");
2463 if (msf->frame >= 75)
2464 printk("aztcd: Error hsg2msf address Frames\n");
2465#endif
2466 azt_bin2bcd(&msf->min); /* convert to BCD */
2467 azt_bin2bcd(&msf->sec);
2468 azt_bin2bcd(&msf->frame);
2469}
2470
2471static long azt_msf2hsg(struct msf *mp)
2472{
2473 return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75
2474 + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET;
2475}
2476
2477static void azt_bin2bcd(unsigned char *p)
2478{
2479 int u, t;
2480
2481 u = *p % 10;
2482 t = *p / 10;
2483 *p = u | (t << 4);
2484}
2485
2486static int azt_bcd2bin(unsigned char bcd)
2487{
2488 return (bcd >> 4) * 10 + (bcd & 0xF);
2489}
2490
2491MODULE_LICENSE("GPL");
2492MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR);