1 /*
2 	linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
3 
4 	Copyright (C) 1992  Martin Harriss
5 	Portions Copyright (C) 2001 Red Hat
6 
7 	martin@bdsi.com (no longer valid - where are you now, Martin?)
8 
9 	This program is free software; you can redistribute it and/or modify
10 	it under the terms of the GNU General Public License as published by
11 	the Free Software Foundation; either version 2, or (at your option)
12 	any later version.
13 
14 	This program is distributed in the hope that it will be useful,
15 	but WITHOUT ANY WARRANTY; without even the implied warranty of
16 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 	GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to the Free Software
21 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 	HISTORY
24 
25 	0.1	First attempt - internal use only
26 	0.2	Cleaned up delays and use of timer - alpha release
27 	0.3	Audio support added
28 	0.3.1 Changes for mitsumi CRMC LU005S march version
29 		   (stud11@cc4.kuleuven.ac.be)
30         0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
31 		   (Jon Tombs <jon@robots.ox.ac.uk>)
32         0.3.3 Added more #defines and mcd_setup()
33    		   (Jon Tombs <jon@gtex02.us.es>)
34 
35 	October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
36 	Braunschweig, Germany: rework to speed up data read operation.
37 	Also enabled definition of irq and address from bootstrap, using the
38 	environment.
39 	November 93 added code for FX001 S,D (single & double speed).
40 	February 94 added code for broken M 5/6 series of 16-bit single speed.
41 
42 
43         0.4
44         Added support for loadable MODULEs, so mcd can now also be loaded by
45         insmod and removed by rmmod during runtime.
46         Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
47 
48 	0.5
49 	I added code for FX001 D to drop from double speed to single speed
50 	when encountering errors... this helps with some "problematic" CD's
51 	that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
52 	severely scratched, or possibly slightly warped! I have noticed that
53 	the Mitsumi 2x/4x drives are just less tolerant and the firmware is
54 	not smart enough to drop speed,	so let's just kludge it with software!
55 	****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
56 	Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
57 	even WORSE! ;)
58 	** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
59 	certain "large" CD's that have data on the outside edge in your
60 	DOS DRIVERS .... Accuracy counts... speed is secondary ;)
61 	17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
62 	07 July 1995 Modifications by Andrew J. Kroll
63 
64 	Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
65 
66 	Michael K. Johnson <johnsonm@redhat.com> added retries on open
67 	for slow drives which take a while to recognize that they contain
68 	a CD.
69 
70 	November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
71 	March    1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
72 
73 	November 1999 -- Make kernel-parameter implementation work with 2.3.x
74 	                 Removed init_module & cleanup_module in favor of
75 			 module_init & module_exit.
76 			 Torben Mathiasen <tmm@image.dk>
77 
78 	September 2001 - Reformatted and cleaned up the code
79 			 Alan Cox <alan@redhat.com>
80 */
81 
82 #include <linux/module.h>
83 
84 #include <linux/errno.h>
85 #include <linux/signal.h>
86 #include <linux/sched.h>
87 #include <linux/mm.h>
88 #include <linux/timer.h>
89 #include <linux/fs.h>
90 #include <linux/kernel.h>
91 #include <linux/devfs_fs_kernel.h>
92 #include <linux/cdrom.h>
93 #include <linux/ioport.h>
94 #include <linux/string.h>
95 #include <linux/delay.h>
96 #include <linux/init.h>
97 #include <linux/config.h>
98 
99 /* #define REALLY_SLOW_IO  */
100 #include <asm/system.h>
101 #include <asm/io.h>
102 #include <asm/uaccess.h>
103 
104 #define MAJOR_NR MITSUMI_CDROM_MAJOR
105 #include <linux/blk.h>
106 
107 #define mcd_port mcd		/* for compatible parameter passing with "insmod" */
108 #include "mcd.h"
109 
110 static int mcd_blocksizes[1];
111 
112 
113 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
114 static int mcdDouble;
115 
116 /* How many sectors to hold at 1x speed counter */
117 static int mcd1xhold;
118 
119 /* Is the drive connected properly and responding?? */
120 static int mcdPresent;
121 
122 #define QUICK_LOOP_DELAY udelay(45)	/* use udelay */
123 #define QUICK_LOOP_COUNT 20
124 
125 #define CURRENT_VALID \
126 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
127 && CURRENT -> sector != -1)
128 
129 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
130 #define MCD_BUF_SIZ 16
131 static volatile int mcd_transfer_is_active;
132 static char mcd_buf[2048 * MCD_BUF_SIZ];	/* buffer for block size conversion */
133 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
134 static volatile int mcd_buf_in, mcd_buf_out = -1;
135 static volatile int mcd_error;
136 static int mcd_open_count;
137 enum mcd_state_e {
138 	MCD_S_IDLE,		/* 0 */
139 	MCD_S_START,		/* 1 */
140 	MCD_S_MODE,		/* 2 */
141 	MCD_S_READ,		/* 3 */
142 	MCD_S_DATA,		/* 4 */
143 	MCD_S_STOP,		/* 5 */
144 	MCD_S_STOPPING		/* 6 */
145 };
146 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
147 static int mcd_mode = -1;
148 static int MCMD_DATA_READ = MCMD_PLAY_READ;
149 
150 #define READ_TIMEOUT 3000
151 
152 int mitsumi_bug_93_wait;
153 
154 static short mcd_port = CONFIG_MCD_BASE;	/* used as "mcd" by "insmod" */
155 static int mcd_irq = CONFIG_MCD_IRQ;	/* must directly follow mcd_port */
156 MODULE_PARM(mcd, "1-2i");
157 
158 static int McdTimeout, McdTries;
159 static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
160 
161 static struct mcd_DiskInfo DiskInfo;
162 static struct mcd_Toc Toc[MAX_TRACKS];
163 static struct mcd_Play_msf mcd_Play;
164 
165 static int audioStatus;
166 static char mcdDiskChanged;
167 static char tocUpToDate;
168 static char mcdVersion;
169 
170 static void mcd_transfer(void);
171 static void mcd_poll(unsigned long dummy);
172 static void mcd_invalidate_buffers(void);
173 static void hsg2msf(long hsg, struct msf *msf);
174 static void bin2bcd(unsigned char *p);
175 static int bcd2bin(unsigned char bcd);
176 static int mcdStatus(void);
177 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
178 static int getMcdStatus(int timeout);
179 static int GetQChannelInfo(struct mcd_Toc *qp);
180 static int updateToc(void);
181 static int GetDiskInfo(void);
182 static int GetToc(void);
183 static int getValue(unsigned char *result);
184 static int mcd_open(struct cdrom_device_info *cdi, int purpose);
185 static void mcd_release(struct cdrom_device_info *cdi);
186 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
187 static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
188 int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
189 		    void *arg);
190 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
191 
192 struct block_device_operations mcd_bdops =
193 {
194 	owner:			THIS_MODULE,
195 	open:			cdrom_open,
196 	release:		cdrom_release,
197 	ioctl:			cdrom_ioctl,
198 	check_media_change:	cdrom_media_changed,
199 };
200 
201 static struct timer_list mcd_timer;
202 
203 static struct cdrom_device_ops mcd_dops = {
204 	open:mcd_open,
205 	release:mcd_release,
206 	drive_status:mcd_drive_status,
207 	media_changed:mcd_media_changed,
208 	tray_move:mcd_tray_move,
209 	audio_ioctl:mcd_audio_ioctl,
210 	capability:CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
211 	    CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
212 };
213 
214 static struct cdrom_device_info mcd_info = {
215 	ops:&mcd_dops,
216 	speed:2,
217 	capacity:1,
218 	name:"mcd",
219 };
220 
221 #ifndef MODULE
mcd_setup(char * str)222 static int __init mcd_setup(char *str)
223 {
224 	int ints[9];
225 
226 	(void) get_options(str, ARRAY_SIZE(ints), ints);
227 
228 	if (ints[0] > 0)
229 		mcd_port = ints[1];
230 	if (ints[0] > 1)
231 		mcd_irq = ints[2];
232 	if (ints[0] > 2)
233 		mitsumi_bug_93_wait = ints[3];
234 
235 	return 1;
236 }
237 
238 __setup("mcd=", mcd_setup);
239 
240 #endif				/* MODULE */
241 
mcd_media_changed(struct cdrom_device_info * cdi,int disc_nr)242 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
243 {
244 	return 0;
245 }
246 
247 
248 /*
249  * Do a 'get status' command and get the result.  Only use from the top half
250  * because it calls 'getMcdStatus' which sleeps.
251  */
252 
statusCmd(void)253 static int statusCmd(void)
254 {
255 	int st = -1, retry;
256 
257 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
258 		/* send get-status cmd */
259 		outb(MCMD_GET_STATUS, MCDPORT(0));
260 
261 		st = getMcdStatus(MCD_STATUS_DELAY);
262 		if (st != -1)
263 			break;
264 	}
265 
266 	return st;
267 }
268 
269 
270 /*
271  * Send a 'Play' command and get the status.  Use only from the top half.
272  */
273 
mcdPlay(struct mcd_Play_msf * arg)274 static int mcdPlay(struct mcd_Play_msf *arg)
275 {
276 	int retry, st = -1;
277 
278 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
279 		sendMcdCmd(MCMD_PLAY_READ, arg);
280 		st = getMcdStatus(2 * MCD_STATUS_DELAY);
281 		if (st != -1)
282 			break;
283 	}
284 
285 	return st;
286 }
287 
288 
mcd_tray_move(struct cdrom_device_info * cdi,int position)289 static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
290 {
291 	int i;
292 	if (position) {
293 		/*  Eject */
294 		/* all drives can at least stop! */
295 		if (audioStatus == CDROM_AUDIO_PLAY) {
296 			outb(MCMD_STOP, MCDPORT(0));
297 			i = getMcdStatus(MCD_STATUS_DELAY);
298 		}
299 
300 		audioStatus = CDROM_AUDIO_NO_STATUS;
301 
302 		outb(MCMD_EJECT, MCDPORT(0));
303 		/*
304 		 * the status (i) shows failure on all but the FX drives.
305 		 * But nothing we can do about that in software!
306 		 * So just read the status and forget it. - Jon.
307 		 */
308 		i = getMcdStatus(MCD_STATUS_DELAY);
309 		return 0;
310 	} else
311 		return -EINVAL;
312 }
313 
msf2hsg(struct msf * mp)314 long msf2hsg(struct msf *mp)
315 {
316 	return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
317 }
318 
319 
mcd_audio_ioctl(struct cdrom_device_info * cdi,unsigned int cmd,void * arg)320 int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
321 		    void *arg)
322 {
323 	int i, st;
324 	struct mcd_Toc qInfo;
325 	struct cdrom_ti *ti;
326 	struct cdrom_tochdr *tocHdr;
327 	struct cdrom_msf *msf;
328 	struct cdrom_subchnl *subchnl;
329 	struct cdrom_tocentry *entry;
330 	struct mcd_Toc *tocPtr;
331 	struct cdrom_volctrl *volctrl;
332 
333 	st = statusCmd();
334 	if (st < 0)
335 		return -EIO;
336 
337 	if (!tocUpToDate) {
338 		i = updateToc();
339 		if (i < 0)
340 			return i;	/* error reading TOC */
341 	}
342 
343 	switch (cmd) {
344 	case CDROMSTART:	/* Spin up the drive */
345 		/* Don't think we can do this.  Even if we could,
346 		 * I think the drive times out and stops after a while
347 		 * anyway.  For now, ignore it.
348 		 */
349 
350 		return 0;
351 
352 	case CDROMSTOP:	/* Spin down the drive */
353 		outb(MCMD_STOP, MCDPORT(0));
354 		i = getMcdStatus(MCD_STATUS_DELAY);
355 
356 		/* should we do anything if it fails? */
357 
358 		audioStatus = CDROM_AUDIO_NO_STATUS;
359 		return 0;
360 
361 	case CDROMPAUSE:	/* Pause the drive */
362 		if (audioStatus != CDROM_AUDIO_PLAY)
363 			return -EINVAL;
364 
365 		outb(MCMD_STOP, MCDPORT(0));
366 		i = getMcdStatus(MCD_STATUS_DELAY);
367 
368 		if (GetQChannelInfo(&qInfo) < 0) {
369 			/* didn't get q channel info */
370 
371 			audioStatus = CDROM_AUDIO_NO_STATUS;
372 			return 0;
373 		}
374 
375 		mcd_Play.start = qInfo.diskTime;	/* remember restart point */
376 
377 		audioStatus = CDROM_AUDIO_PAUSED;
378 		return 0;
379 
380 	case CDROMRESUME:	/* Play it again, Sam */
381 		if (audioStatus != CDROM_AUDIO_PAUSED)
382 			return -EINVAL;
383 
384 		/* restart the drive at the saved position. */
385 
386 		i = mcdPlay(&mcd_Play);
387 		if (i < 0) {
388 			audioStatus = CDROM_AUDIO_ERROR;
389 			return -EIO;
390 		}
391 
392 		audioStatus = CDROM_AUDIO_PLAY;
393 		return 0;
394 
395 	case CDROMPLAYTRKIND:	/* Play a track.  This currently ignores index. */
396 
397 		ti = (struct cdrom_ti *) arg;
398 
399 		if (ti->cdti_trk0 < DiskInfo.first
400 		    || ti->cdti_trk0 > DiskInfo.last
401 		    || ti->cdti_trk1 < ti->cdti_trk0) {
402 			return -EINVAL;
403 		}
404 
405 		if (ti->cdti_trk1 > DiskInfo.last)
406 			ti->cdti_trk1 = DiskInfo.last;
407 
408 		mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
409 		mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
410 
411 #ifdef MCD_DEBUG
412 		printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
413 		       mcd_Play.start.min, mcd_Play.start.sec,
414 		       mcd_Play.start.frame, mcd_Play.end.min,
415 		       mcd_Play.end.sec, mcd_Play.end.frame);
416 #endif
417 
418 		i = mcdPlay(&mcd_Play);
419 		if (i < 0) {
420 			audioStatus = CDROM_AUDIO_ERROR;
421 			return -EIO;
422 		}
423 
424 		audioStatus = CDROM_AUDIO_PLAY;
425 		return 0;
426 
427 	case CDROMPLAYMSF:	/* Play starting at the given MSF address. */
428 
429 		if (audioStatus == CDROM_AUDIO_PLAY) {
430 			outb(MCMD_STOP, MCDPORT(0));
431 			i = getMcdStatus(MCD_STATUS_DELAY);
432 			audioStatus = CDROM_AUDIO_NO_STATUS;
433 		}
434 
435 		msf = (struct cdrom_msf *) arg;
436 
437 		/* convert to bcd */
438 
439 		bin2bcd(&msf->cdmsf_min0);
440 		bin2bcd(&msf->cdmsf_sec0);
441 		bin2bcd(&msf->cdmsf_frame0);
442 		bin2bcd(&msf->cdmsf_min1);
443 		bin2bcd(&msf->cdmsf_sec1);
444 		bin2bcd(&msf->cdmsf_frame1);
445 
446 		mcd_Play.start.min = msf->cdmsf_min0;
447 		mcd_Play.start.sec = msf->cdmsf_sec0;
448 		mcd_Play.start.frame = msf->cdmsf_frame0;
449 		mcd_Play.end.min = msf->cdmsf_min1;
450 		mcd_Play.end.sec = msf->cdmsf_sec1;
451 		mcd_Play.end.frame = msf->cdmsf_frame1;
452 
453 #ifdef MCD_DEBUG
454 		printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
455 		       mcd_Play.start.min, mcd_Play.start.sec,
456 		       mcd_Play.start.frame, mcd_Play.end.min,
457 		       mcd_Play.end.sec, mcd_Play.end.frame);
458 #endif
459 
460 		i = mcdPlay(&mcd_Play);
461 		if (i < 0) {
462 			audioStatus = CDROM_AUDIO_ERROR;
463 			return -EIO;
464 		}
465 
466 		audioStatus = CDROM_AUDIO_PLAY;
467 		return 0;
468 
469 	case CDROMREADTOCHDR:	/* Read the table of contents header */
470 		tocHdr = (struct cdrom_tochdr *) arg;
471 		tocHdr->cdth_trk0 = DiskInfo.first;
472 		tocHdr->cdth_trk1 = DiskInfo.last;
473 		return 0;
474 
475 	case CDROMREADTOCENTRY:	/* Read an entry in the table of contents */
476 		entry = (struct cdrom_tocentry *) arg;
477 		if (entry->cdte_track == CDROM_LEADOUT)
478 			tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
479 
480 		else if (entry->cdte_track > DiskInfo.last
481 			 || entry->cdte_track < DiskInfo.first)
482 			return -EINVAL;
483 
484 		else
485 			tocPtr = &Toc[entry->cdte_track];
486 
487 		entry->cdte_adr = tocPtr->ctrl_addr;
488 		entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
489 
490 		if (entry->cdte_format == CDROM_LBA)
491 			entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
492 
493 		else if (entry->cdte_format == CDROM_MSF) {
494 			entry->cdte_addr.msf.minute =
495 			    bcd2bin(tocPtr->diskTime.min);
496 			entry->cdte_addr.msf.second =
497 			    bcd2bin(tocPtr->diskTime.sec);
498 			entry->cdte_addr.msf.frame =
499 			    bcd2bin(tocPtr->diskTime.frame);
500 		}
501 
502 		else
503 			return -EINVAL;
504 
505 		return 0;
506 
507 	case CDROMSUBCHNL:	/* Get subchannel info */
508 
509 		subchnl = (struct cdrom_subchnl *) arg;
510 		if (GetQChannelInfo(&qInfo) < 0)
511 			return -EIO;
512 
513 		subchnl->cdsc_audiostatus = audioStatus;
514 		subchnl->cdsc_adr = qInfo.ctrl_addr;
515 		subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
516 		subchnl->cdsc_trk = bcd2bin(qInfo.track);
517 		subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
518 		subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
519 		subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
520 		subchnl->cdsc_absaddr.msf.frame  = bcd2bin(qInfo.diskTime.frame);
521 		subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
522 		subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
523 		subchnl->cdsc_reladdr.msf.frame  = bcd2bin(qInfo.trackTime.frame);
524 		return (0);
525 
526 	case CDROMVOLCTRL:	/* Volume control */
527 		volctrl = (struct cdrom_volctrl *) arg;
528 		outb(MCMD_SET_VOLUME, MCDPORT(0));
529 		outb(volctrl->channel0, MCDPORT(0));
530 		outb(255, MCDPORT(0));
531 		outb(volctrl->channel1, MCDPORT(0));
532 		outb(255, MCDPORT(0));
533 
534 		i = getMcdStatus(MCD_STATUS_DELAY);
535 		if (i < 0)
536 			return -EIO;
537 
538 		{
539 			char a, b, c, d;
540 
541 			getValue(&a);
542 			getValue(&b);
543 			getValue(&c);
544 			getValue(&d);
545 		}
546 
547 		return 0;
548 
549 	default:
550 		return -EINVAL;
551 	}
552 }
553 
554 /*
555  * Take care of the different block sizes between cdrom and Linux.
556  * When Linux gets variable block sizes this will probably go away.
557  */
558 
mcd_transfer(void)559 static void mcd_transfer(void)
560 {
561 	if (CURRENT_VALID) {
562 		while (CURRENT->nr_sectors) {
563 			int bn = CURRENT->sector / 4;
564 			int i;
565 			for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn;
566 			     ++i);
567 			if (i < MCD_BUF_SIZ) {
568 				int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
569 				int nr_sectors = 4 - (CURRENT->sector & 3);
570 				if (mcd_buf_out != i) {
571 					mcd_buf_out = i;
572 					if (mcd_buf_bn[i] != bn) {
573 						mcd_buf_out = -1;
574 						continue;
575 					}
576 				}
577 				if (nr_sectors > CURRENT->nr_sectors)
578 					nr_sectors = CURRENT->nr_sectors;
579 				memcpy(CURRENT->buffer, mcd_buf + offs,
580 				       nr_sectors * 512);
581 				CURRENT->nr_sectors -= nr_sectors;
582 				CURRENT->sector += nr_sectors;
583 				CURRENT->buffer += nr_sectors * 512;
584 			} else {
585 				mcd_buf_out = -1;
586 				break;
587 			}
588 		}
589 	}
590 }
591 
592 
593 /*
594  * We only seem to get interrupts after an error.
595  * Just take the interrupt and clear out the status reg.
596  */
597 
mcd_interrupt(int irq,void * dev_id,struct pt_regs * regs)598 static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
599 {
600 	int st;
601 
602 	st = inb(MCDPORT(1)) & 0xFF;
603 	test1(printk("<int1-%02X>", st));
604 	if (!(st & MFL_STATUS)) {
605 		st = inb(MCDPORT(0)) & 0xFF;
606 		test1(printk("<int0-%02X>", st));
607 		if ((st & 0xFF) != 0xFF)
608 			mcd_error = st ? st & 0xFF : -1;
609 	}
610 }
611 
612 
do_mcd_request(request_queue_t * q)613 static void do_mcd_request(request_queue_t * q)
614 {
615 	test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
616 	       CURRENT->nr_sectors));
617 
618 		mcd_transfer_is_active = 1;
619 	while (CURRENT_VALID) {
620 		if (CURRENT->bh) {
621 			if (!buffer_locked(CURRENT->bh))
622 				panic(DEVICE_NAME ": block not locked");
623 		}
624 		mcd_transfer();
625 		if (CURRENT->nr_sectors == 0) {
626 			end_request(1);
627 		} else {
628 			mcd_buf_out = -1;	/* Want to read a block not in buffer */
629 			if (mcd_state == MCD_S_IDLE) {
630 				if (!tocUpToDate) {
631 					if (updateToc() < 0) {
632 						while (CURRENT_VALID)
633 							end_request(0);
634 						break;
635 					}
636 				}
637 				mcd_state = MCD_S_START;
638 				McdTries = 5;
639 				mcd_timer.function = mcd_poll;
640 				mod_timer(&mcd_timer, jiffies + 1);
641 			}
642 			break;
643 		}
644 	}
645 	mcd_transfer_is_active = 0;
646 	test2(printk(" do_mcd_request ends\n"));
647 }
648 
649 
650 
mcd_poll(unsigned long dummy)651 static void mcd_poll(unsigned long dummy)
652 {
653 	int st;
654 
655 
656 	if (mcd_error) {
657 		if (mcd_error & 0xA5) {
658 			printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
659 			if (mcd_error & 0x80)
660 				printk(" (Door open)");
661 			if (mcd_error & 0x20)
662 				printk(" (Disk changed)");
663 			if (mcd_error & 0x04) {
664 				printk(" (Read error)");	/* Bitch about the problem. */
665 
666 				/* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
667 				/* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
668 				/* But I find that rather HANDY!!! */
669 				/* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
670 				/* AJK [06/17/95] */
671 
672 				/* Slap the CD down to single speed! */
673 				if (mcdDouble == 1
674 				    && McdTries == MCD_RETRY_ATTEMPTS
675 				    && MCMD_DATA_READ == MCMD_2X_READ) {
676 					MCMD_DATA_READ = MCMD_PLAY_READ;	/* Uhhh, Ummmm, muhuh-huh! */
677 					mcd1xhold = SINGLE_HOLD_SECTORS;	/* Hey Beavis! */
678 					printk(" Speed now 1x");	/* Pull my finger! */
679 				}
680 			}
681 			printk("\n");
682 			mcd_invalidate_buffers();
683 #ifdef WARN_IF_READ_FAILURE
684 			if (McdTries == MCD_RETRY_ATTEMPTS)
685 				printk(KERN_ERR "mcd: read of block %d failed\n",
686 				       mcd_next_bn);
687 #endif
688 			if (!McdTries--) {
689 				/* Nuts! This cd is ready for recycling! */
690 				/* When WAS the last time YOU cleaned it CORRECTLY?! */
691 				printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
692 				     mcd_next_bn);
693 				if (mcd_transfer_is_active) {
694 					McdTries = 0;
695 					goto ret;
696 				}
697 				if (CURRENT_VALID)
698 					end_request(0);
699 				McdTries = MCD_RETRY_ATTEMPTS;
700 			}
701 		}
702 		mcd_error = 0;
703 		mcd_state = MCD_S_STOP;
704 	}
705 	/* Switch back to Double speed if enough GOOD sectors were read! */
706 
707 	/* Are we a double speed with a crappy CD?! */
708 	if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
709 	    && MCMD_DATA_READ == MCMD_PLAY_READ) {
710 		/* We ARE a double speed and we ARE bitching! */
711 		if (mcd1xhold == 0) {	/* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
712 			MCMD_DATA_READ = MCMD_2X_READ;	/* Uhhh... BACK You GO! */
713 			printk(KERN_INFO "mcd: Switching back to 2X speed!\n");	/* Tell 'em! */
714 		} else
715 			mcd1xhold--;	/* No?! Count down the good reads some more... */
716 		/* and try, try again! */
717 	}
718 
719 immediately:
720 	switch (mcd_state) {
721 	case MCD_S_IDLE:
722 		test3(printk("MCD_S_IDLE\n"));
723 		goto out;
724 
725 	case MCD_S_START:
726 		test3(printk("MCD_S_START\n"));
727 		outb(MCMD_GET_STATUS, MCDPORT(0));
728 		mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
729 		McdTimeout = 3000;
730 		break;
731 
732 	case MCD_S_MODE:
733 		test3(printk("MCD_S_MODE\n"));
734 		if ((st = mcdStatus()) != -1) {
735 			if (st & MST_DSK_CHG) {
736 				mcdDiskChanged = 1;
737 				tocUpToDate = 0;
738 				mcd_invalidate_buffers();
739 			}
740 
741 set_mode_immediately:
742 			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
743 				mcdDiskChanged = 1;
744 				tocUpToDate = 0;
745 				if (mcd_transfer_is_active) {
746 					mcd_state = MCD_S_START;
747 					goto immediately;
748 				}
749 				printk(KERN_INFO);
750 				printk((st & MST_DOOR_OPEN) ?
751 				       "mcd: door open\n" :
752 				       "mcd: disk removed\n");
753 				mcd_state = MCD_S_IDLE;
754 				while (CURRENT_VALID)
755 					end_request(0);
756 				goto out;
757 			}
758 			outb(MCMD_SET_MODE, MCDPORT(0));
759 			outb(1, MCDPORT(0));
760 			mcd_mode = 1;
761 			mcd_state = MCD_S_READ;
762 			McdTimeout = 3000;
763 		}
764 		break;
765 
766 	case MCD_S_READ:
767 		test3(printk("MCD_S_READ\n"));
768 		if ((st = mcdStatus()) != -1) {
769 			if (st & MST_DSK_CHG) {
770 				mcdDiskChanged = 1;
771 				tocUpToDate = 0;
772 				mcd_invalidate_buffers();
773 			}
774 
775 read_immediately:
776 			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
777 				mcdDiskChanged = 1;
778 				tocUpToDate = 0;
779 				if (mcd_transfer_is_active) {
780 					mcd_state = MCD_S_START;
781 					goto immediately;
782 				}
783 				printk(KERN_INFO);
784 				printk((st & MST_DOOR_OPEN) ?
785 				       "mcd: door open\n" :
786 				       "mcd: disk removed\n");
787 				mcd_state = MCD_S_IDLE;
788 				while (CURRENT_VALID)
789 					end_request(0);
790 				goto out;
791 			}
792 
793 			if (CURRENT_VALID) {
794 				struct mcd_Play_msf msf;
795 				mcd_next_bn = CURRENT->sector / 4;
796 				hsg2msf(mcd_next_bn, &msf.start);
797 				msf.end.min = ~0;
798 				msf.end.sec = ~0;
799 				msf.end.frame = ~0;
800 				sendMcdCmd(MCMD_DATA_READ, &msf);
801 				mcd_state = MCD_S_DATA;
802 				McdTimeout = READ_TIMEOUT;
803 			} else {
804 				mcd_state = MCD_S_STOP;
805 				goto immediately;
806 			}
807 
808 		}
809 		break;
810 
811 	case MCD_S_DATA:
812 		test3(printk("MCD_S_DATA\n"));
813 		st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
814 data_immediately:
815 		test5(printk("Status %02x\n", st))
816 		switch (st) {
817 		case MFL_DATA:
818 #ifdef WARN_IF_READ_FAILURE
819 			if (McdTries == 5)
820 				printk(KERN_WARNING "mcd: read of block %d failed\n",
821 				       mcd_next_bn);
822 #endif
823 			if (!McdTries--) {
824 				printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
825 				if (mcd_transfer_is_active) {
826 					McdTries = 0;
827 					break;
828 				}
829 				if (CURRENT_VALID)
830 					end_request(0);
831 				McdTries = 5;
832 			}
833 			mcd_state = MCD_S_START;
834 			McdTimeout = READ_TIMEOUT;
835 			goto immediately;
836 
837 		case MFL_STATUSorDATA:
838 			break;
839 
840 		default:
841 			McdTries = 5;
842 			if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
843 				mcd_state = MCD_S_STOP;
844 				goto immediately;
845 			}
846 			mcd_buf_bn[mcd_buf_in] = -1;
847 			insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
848 				  2048);
849 			mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
850 			if (mcd_buf_out == -1)
851 				mcd_buf_out = mcd_buf_in;
852 			mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
853 			if (!mcd_transfer_is_active) {
854 				while (CURRENT_VALID) {
855 					mcd_transfer();
856 					if (CURRENT->nr_sectors == 0)
857 						end_request(1);
858 					else
859 						break;
860 				}
861 			}
862 
863 			if (CURRENT_VALID
864 			    && (CURRENT->sector / 4 < mcd_next_bn ||
865 				CURRENT->sector / 4 > mcd_next_bn + 16)) {
866 				mcd_state = MCD_S_STOP;
867 				goto immediately;
868 			}
869 			McdTimeout = READ_TIMEOUT;
870 			{
871 				int count = QUICK_LOOP_COUNT;
872 				while (count--) {
873 					QUICK_LOOP_DELAY;
874 					if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
875 						test4(printk(" %d ", QUICK_LOOP_COUNT - count));
876 						goto data_immediately;
877 					}
878 				}
879 				test4(printk("ended "));
880 			}
881 			break;
882 		}
883 		break;
884 
885 	case MCD_S_STOP:
886 		test3(printk("MCD_S_STOP\n"));
887 		if (!mitsumi_bug_93_wait)
888 			goto do_not_work_around_mitsumi_bug_93_1;
889 
890 		McdTimeout = mitsumi_bug_93_wait;
891 		mcd_state = 9 + 3 + 1;
892 		break;
893 
894 	case 9 + 3 + 1:
895 		if (McdTimeout)
896 			break;
897 
898 do_not_work_around_mitsumi_bug_93_1:
899 		outb(MCMD_STOP, MCDPORT(0));
900 		if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
901 			int i = 4096;
902 			do {
903 				inb(MCDPORT(0));
904 			} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
905 			outb(MCMD_STOP, MCDPORT(0));
906 			if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
907 				i = 4096;
908 				do {
909 					inb(MCDPORT(0));
910 				} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
911 				outb(MCMD_STOP, MCDPORT(0));
912 			}
913 		}
914 
915 		mcd_state = MCD_S_STOPPING;
916 		McdTimeout = 1000;
917 		break;
918 
919 	case MCD_S_STOPPING:
920 		test3(printk("MCD_S_STOPPING\n"));
921 		if ((st = mcdStatus()) == -1 && McdTimeout)
922 			break;
923 
924 		if ((st != -1) && (st & MST_DSK_CHG)) {
925 			mcdDiskChanged = 1;
926 			tocUpToDate = 0;
927 			mcd_invalidate_buffers();
928 		}
929 		if (!mitsumi_bug_93_wait)
930 			goto do_not_work_around_mitsumi_bug_93_2;
931 
932 		McdTimeout = mitsumi_bug_93_wait;
933 		mcd_state = 9 + 3 + 2;
934 		break;
935 
936 	case 9 + 3 + 2:
937 		if (McdTimeout)
938 			break;
939 		st = -1;
940 
941 do_not_work_around_mitsumi_bug_93_2:
942 		test3(printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode));
943 		if (CURRENT_VALID) {
944 			if (st != -1) {
945 				if (mcd_mode == 1)
946 					goto read_immediately;
947 				else
948 					goto set_mode_immediately;
949 			} else {
950 				mcd_state = MCD_S_START;
951 				McdTimeout = 1;
952 			}
953 		} else {
954 			mcd_state = MCD_S_IDLE;
955 			goto out;
956 		}
957 		break;
958 	default:
959 		printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
960 		goto out;
961 	}
962 ret:
963 	if (!McdTimeout--) {
964 		printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
965 		mcd_state = MCD_S_STOP;
966 	}
967 	mcd_timer.function = mcd_poll;
968 	mod_timer(&mcd_timer, jiffies + 1);
969 out:
970 	return;
971 }
972 
mcd_invalidate_buffers(void)973 static void mcd_invalidate_buffers(void)
974 {
975 	int i;
976 	for (i = 0; i < MCD_BUF_SIZ; ++i)
977 		mcd_buf_bn[i] = -1;
978 	mcd_buf_out = -1;
979 }
980 
981 /*
982  * Open the device special file.  Check that a disk is in.
983  */
mcd_open(struct cdrom_device_info * cdi,int purpose)984 static int mcd_open(struct cdrom_device_info *cdi, int purpose)
985 {
986 	int st, count = 0;
987 	if (mcdPresent == 0)
988 		return -ENXIO;	/* no hardware */
989 
990 	if (mcd_open_count || mcd_state != MCD_S_IDLE)
991 		goto bump_count;
992 
993 	mcd_invalidate_buffers();
994 	do {
995 		st = statusCmd();	/* check drive status */
996 		if (st == -1)
997 			goto err_out;	/* drive doesn't respond */
998 		if ((st & MST_READY) == 0) {	/* no disk? wait a sec... */
999 			current->state = TASK_INTERRUPTIBLE;
1000 			schedule_timeout(HZ);
1001 		}
1002 	} while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1003 
1004 	if (updateToc() < 0)
1005 		goto err_out;
1006 
1007 bump_count:
1008 	++mcd_open_count;
1009 	return 0;
1010 
1011 err_out:
1012 	return -EIO;
1013 }
1014 
1015 
1016 /*
1017  * On close, we flush all mcd blocks from the buffer cache.
1018  */
mcd_release(struct cdrom_device_info * cdi)1019 static void mcd_release(struct cdrom_device_info *cdi)
1020 {
1021 	if (!--mcd_open_count) {
1022 		mcd_invalidate_buffers();
1023 	}
1024 }
1025 
1026 
1027 
1028 /* This routine gets called during initialization if things go wrong,
1029  * and is used in mcd_exit as well. */
cleanup(int level)1030 static void cleanup(int level)
1031 {
1032 	switch (level) {
1033 	case 3:
1034 		if (unregister_cdrom(&mcd_info)) {
1035 			printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1036 			return;
1037 		}
1038 		free_irq(mcd_irq, NULL);
1039 	case 2:
1040 		release_region(mcd_port, 4);
1041 	case 1:
1042 		if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
1043 			printk(KERN_WARNING "Can't unregister major mcd\n");
1044 			return;
1045 		}
1046 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1047 	default:;
1048 	}
1049 }
1050 
1051 
1052 
1053 /*
1054  * Test for presence of drive and initialize it.  Called at boot time.
1055  */
1056 
mcd_init(void)1057 int __init mcd_init(void)
1058 {
1059 	int count;
1060 	unsigned char result[3];
1061 	char msg[80];
1062 
1063 	if (mcd_port <= 0 || mcd_irq <= 0) {
1064 		printk(KERN_INFO "mcd: not probing.\n");
1065 		return -EIO;
1066 	}
1067 
1068 	if (devfs_register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) {
1069 		printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);
1070 		return -EIO;
1071 	}
1072 	if (check_region(mcd_port, 4)) {
1073 		cleanup(1);
1074 		printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
1075 		return -EIO;
1076 	}
1077 
1078 	blksize_size[MAJOR_NR] = mcd_blocksizes;
1079 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1080 	read_ahead[MAJOR_NR] = 4;
1081 
1082 	/* check for card */
1083 
1084 	outb(0, MCDPORT(1));	/* send reset */
1085 	for (count = 0; count < 2000000; count++)
1086 		(void) inb(MCDPORT(1));	/* delay a bit */
1087 
1088 	outb(0x40, MCDPORT(0));	/* send get-stat cmd */
1089 	for (count = 0; count < 2000000; count++)
1090 		if (!(inb(MCDPORT(1)) & MFL_STATUS))
1091 			break;
1092 
1093 	if (count >= 2000000) {
1094 		printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
1095 		       mcd_port, mcd_irq);
1096 		cleanup(1);
1097 		return -EIO;
1098 	}
1099 	count = inb(MCDPORT(0));	/* pick up the status */
1100 
1101 	outb(MCMD_GET_VERSION, MCDPORT(0));
1102 	for (count = 0; count < 3; count++)
1103 		if (getValue(result + count)) {
1104 			printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
1105 			       mcd_port);
1106 			cleanup(1);
1107 			return -EIO;
1108 		}
1109 
1110 	if (result[0] == result[1] && result[1] == result[2]) {
1111 		cleanup(1);
1112 		return -EIO;
1113 	}
1114 
1115 	mcdVersion = result[2];
1116 
1117 	if (mcdVersion >= 4)
1118 		outb(4, MCDPORT(2));	/* magic happens */
1119 
1120 	/* don't get the IRQ until we know for sure the drive is there */
1121 
1122 	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
1123 		printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1124 		cleanup(1);
1125 		return -EIO;
1126 	}
1127 
1128 	if (result[1] == 'D') {
1129 		MCMD_DATA_READ = MCMD_2X_READ;
1130 		/* Added flag to drop to 1x speed if too many errors */
1131 		mcdDouble = 1;
1132 	} else
1133 		mcd_info.speed = 1;
1134 	sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1135 		" irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
1136 		mcd_port, mcd_irq);
1137 
1138 	request_region(mcd_port, 4, "mcd");
1139 
1140 	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1141 	outb(0x02, MCDPORT(0));
1142 	outb(0x00, MCDPORT(0));
1143 	getValue(result);
1144 
1145 	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1146 	outb(0x10, MCDPORT(0));
1147 	outb(0x04, MCDPORT(0));
1148 	getValue(result);
1149 
1150 	mcd_invalidate_buffers();
1151 	mcdPresent = 1;
1152 
1153 	mcd_info.dev = MKDEV(MAJOR_NR, 0);
1154 
1155 	if (register_cdrom(&mcd_info) != 0) {
1156 		printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
1157 		cleanup(3);
1158 		return -EIO;
1159 	}
1160 	devfs_plain_cdrom(&mcd_info, &mcd_bdops);
1161 	printk(msg);
1162 
1163 	return 0;
1164 }
1165 
1166 
hsg2msf(long hsg,struct msf * msf)1167 static void hsg2msf(long hsg, struct msf *msf)
1168 {
1169 	hsg += 150;
1170 	msf->min = hsg / 4500;
1171 	hsg %= 4500;
1172 	msf->sec = hsg / 75;
1173 	msf->frame = hsg % 75;
1174 
1175 	bin2bcd(&msf->min);	/* convert to BCD */
1176 	bin2bcd(&msf->sec);
1177 	bin2bcd(&msf->frame);
1178 }
1179 
1180 
bin2bcd(unsigned char * p)1181 static void bin2bcd(unsigned char *p)
1182 {
1183 	int u, t;
1184 
1185 	u = *p % 10;
1186 	t = *p / 10;
1187 	*p = u | (t << 4);
1188 }
1189 
bcd2bin(unsigned char bcd)1190 static int bcd2bin(unsigned char bcd)
1191 {
1192 	return (bcd >> 4) * 10 + (bcd & 0xF);
1193 }
1194 
1195 
1196 /*
1197  * See if a status is ready from the drive and return it
1198  * if it is ready.
1199  */
1200 
mcdStatus(void)1201 static int mcdStatus(void)
1202 {
1203 	int i;
1204 	int st;
1205 
1206 	st = inb(MCDPORT(1)) & MFL_STATUS;
1207 	if (!st) {
1208 		i = inb(MCDPORT(0)) & 0xFF;
1209 		return i;
1210 	} else
1211 		return -1;
1212 }
1213 
1214 
1215 /*
1216  * Send a play or read command to the drive
1217  */
1218 
sendMcdCmd(int cmd,struct mcd_Play_msf * params)1219 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1220 {
1221 	outb(cmd, MCDPORT(0));
1222 	outb(params->start.min, MCDPORT(0));
1223 	outb(params->start.sec, MCDPORT(0));
1224 	outb(params->start.frame, MCDPORT(0));
1225 	outb(params->end.min, MCDPORT(0));
1226 	outb(params->end.sec, MCDPORT(0));
1227 	outb(params->end.frame, MCDPORT(0));
1228 }
1229 
1230 
1231 /*
1232  * Timer interrupt routine to test for status ready from the drive.
1233  * (see the next routine)
1234  */
1235 
mcdStatTimer(unsigned long dummy)1236 static void mcdStatTimer(unsigned long dummy)
1237 {
1238 	if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
1239 		wake_up(&mcd_waitq);
1240 		return;
1241 	}
1242 
1243 	McdTimeout--;
1244 	if (McdTimeout <= 0) {
1245 		wake_up(&mcd_waitq);
1246 		return;
1247 	}
1248 	mcd_timer.function = mcdStatTimer;
1249 	mod_timer(&mcd_timer, jiffies + 1);
1250 }
1251 
1252 
1253 /*
1254  * Wait for a status to be returned from the drive.  The actual test
1255  * (see routine above) is done by the timer interrupt to avoid
1256  * excessive rescheduling.
1257  */
1258 
getMcdStatus(int timeout)1259 static int getMcdStatus(int timeout)
1260 {
1261 	int st;
1262 
1263 	McdTimeout = timeout;
1264 	mcd_timer.function = mcdStatTimer;
1265 	mod_timer(&mcd_timer, jiffies + 1);
1266 	sleep_on(&mcd_waitq);
1267 	if (McdTimeout <= 0)
1268 		return -1;
1269 
1270 	st = inb(MCDPORT(0)) & 0xFF;
1271 	if (st == 0xFF)
1272 		return -1;
1273 
1274 	if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1275 		/* XXX might be an error? look at q-channel? */
1276 		audioStatus = CDROM_AUDIO_COMPLETED;
1277 
1278 	if (st & MST_DSK_CHG) {
1279 		mcdDiskChanged = 1;
1280 		tocUpToDate = 0;
1281 		audioStatus = CDROM_AUDIO_NO_STATUS;
1282 	}
1283 
1284 	return st;
1285 }
1286 
1287 
1288 /* gives current state of the drive This function is quite unreliable,
1289    and should probably be rewritten by someone, eventually... */
1290 
mcd_drive_status(struct cdrom_device_info * cdi,int slot_nr)1291 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1292 {
1293 	int st;
1294 
1295 	st = statusCmd();	/* check drive status */
1296 	if (st == -1)
1297 		return -EIO;	/* drive doesn't respond */
1298 	if ((st & MST_READY))
1299 		return CDS_DISC_OK;
1300 	if ((st & MST_DOOR_OPEN))
1301 		return CDS_TRAY_OPEN;
1302 	if ((st & MST_DSK_CHG))
1303 		return CDS_NO_DISC;
1304 	if ((st & MST_BUSY))
1305 		return CDS_DRIVE_NOT_READY;
1306 	return -EIO;
1307 }
1308 
1309 
1310 /*
1311  * Read a value from the drive.
1312  */
1313 
getValue(unsigned char * result)1314 static int getValue(unsigned char *result)
1315 {
1316 	int count;
1317 	int s;
1318 
1319 	for (count = 0; count < 2000; count++)
1320 		if (!(inb(MCDPORT(1)) & MFL_STATUS))
1321 			break;
1322 
1323 	if (count >= 2000) {
1324 		printk("mcd: getValue timeout\n");
1325 		return -1;
1326 	}
1327 
1328 	s = inb(MCDPORT(0)) & 0xFF;
1329 	*result = (unsigned char) s;
1330 	return 0;
1331 }
1332 
1333 /*
1334  * Read the current Q-channel info.  Also used for reading the
1335  * table of contents.
1336  */
1337 
GetQChannelInfo(struct mcd_Toc * qp)1338 int GetQChannelInfo(struct mcd_Toc *qp)
1339 {
1340 	unsigned char notUsed;
1341 	int retry;
1342 
1343 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1344 		outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1345 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1346 			break;
1347 	}
1348 
1349 	if (retry >= MCD_RETRY_ATTEMPTS)
1350 		return -1;
1351 
1352 	if (getValue(&qp->ctrl_addr) < 0)
1353 		return -1;
1354 	if (getValue(&qp->track) < 0)
1355 		return -1;
1356 	if (getValue(&qp->pointIndex) < 0)
1357 		return -1;
1358 	if (getValue(&qp->trackTime.min) < 0)
1359 		return -1;
1360 	if (getValue(&qp->trackTime.sec) < 0)
1361 		return -1;
1362 	if (getValue(&qp->trackTime.frame) < 0)
1363 		return -1;
1364 	if (getValue(&notUsed) < 0)
1365 		return -1;
1366 	if (getValue(&qp->diskTime.min) < 0)
1367 		return -1;
1368 	if (getValue(&qp->diskTime.sec) < 0)
1369 		return -1;
1370 	if (getValue(&qp->diskTime.frame) < 0)
1371 		return -1;
1372 
1373 	return 0;
1374 }
1375 
1376 /*
1377  * Read the table of contents (TOC) and TOC header if necessary
1378  */
1379 
updateToc(void)1380 static int updateToc(void)
1381 {
1382 	if (tocUpToDate)
1383 		return 0;
1384 
1385 	if (GetDiskInfo() < 0)
1386 		return -EIO;
1387 
1388 	if (GetToc() < 0)
1389 		return -EIO;
1390 
1391 	tocUpToDate = 1;
1392 	return 0;
1393 }
1394 
1395 /*
1396  * Read the table of contents header
1397  */
1398 
GetDiskInfo(void)1399 static int GetDiskInfo(void)
1400 {
1401 	int retry;
1402 
1403 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1404 		outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1405 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1406 			break;
1407 	}
1408 
1409 	if (retry >= MCD_RETRY_ATTEMPTS)
1410 		return -1;
1411 
1412 	if (getValue(&DiskInfo.first) < 0)
1413 		return -1;
1414 	if (getValue(&DiskInfo.last) < 0)
1415 		return -1;
1416 
1417 	DiskInfo.first = bcd2bin(DiskInfo.first);
1418 	DiskInfo.last = bcd2bin(DiskInfo.last);
1419 
1420 #ifdef MCD_DEBUG
1421 	printk
1422 	    ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1423 	     DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
1424 	     DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
1425 	     DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
1426 	     DiskInfo.firstTrack.frame);
1427 #endif
1428 
1429 	if (getValue(&DiskInfo.diskLength.min) < 0)
1430 		return -1;
1431 	if (getValue(&DiskInfo.diskLength.sec) < 0)
1432 		return -1;
1433 	if (getValue(&DiskInfo.diskLength.frame) < 0)
1434 		return -1;
1435 	if (getValue(&DiskInfo.firstTrack.min) < 0)
1436 		return -1;
1437 	if (getValue(&DiskInfo.firstTrack.sec) < 0)
1438 		return -1;
1439 	if (getValue(&DiskInfo.firstTrack.frame) < 0)
1440 		return -1;
1441 
1442 	return 0;
1443 }
1444 
1445 /*
1446  * Read the table of contents (TOC)
1447  */
1448 
GetToc(void)1449 static int GetToc(void)
1450 {
1451 	int i, px;
1452 	int limit;
1453 	int retry;
1454 	struct mcd_Toc qInfo;
1455 
1456 	for (i = 0; i < MAX_TRACKS; i++)
1457 		Toc[i].pointIndex = 0;
1458 
1459 	i = DiskInfo.last + 3;
1460 
1461 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1462 		outb(MCMD_STOP, MCDPORT(0));
1463 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1464 			break;
1465 	}
1466 
1467 	if (retry >= MCD_RETRY_ATTEMPTS)
1468 		return -1;
1469 
1470 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1471 		outb(MCMD_SET_MODE, MCDPORT(0));
1472 		outb(0x05, MCDPORT(0));	/* mode: toc */
1473 		mcd_mode = 0x05;
1474 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1475 			break;
1476 	}
1477 
1478 	if (retry >= MCD_RETRY_ATTEMPTS)
1479 		return -1;
1480 
1481 	for (limit = 300; limit > 0; limit--) {
1482 		if (GetQChannelInfo(&qInfo) < 0)
1483 			break;
1484 
1485 		px = bcd2bin(qInfo.pointIndex);
1486 		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1487 			if (Toc[px].pointIndex == 0) {
1488 				Toc[px] = qInfo;
1489 				i--;
1490 			}
1491 
1492 		if (i <= 0)
1493 			break;
1494 	}
1495 
1496 	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1497 
1498 	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1499 		outb(MCMD_SET_MODE, MCDPORT(0));
1500 		outb(0x01, MCDPORT(0));
1501 		mcd_mode = 1;
1502 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1503 			break;
1504 	}
1505 
1506 #ifdef MCD_DEBUG
1507 	for (i = 1; i <= DiskInfo.last; i++)
1508 		printk
1509 		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1510 		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1511 		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
1512 		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
1513 		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1514 	for (i = 100; i < 103; i++)
1515 		printk
1516 		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1517 		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1518 		     Toc[i].trackTime.min, Toc[i].trackTime.sec,
1519 		     Toc[i].trackTime.frame, Toc[i].diskTime.min,
1520 		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1521 #endif
1522 
1523 	return limit > 0 ? 0 : -1;
1524 }
1525 
mcd_exit(void)1526 void __exit mcd_exit(void)
1527 {
1528 	cleanup(3);
1529 	del_timer_sync(&mcd_timer);
1530 }
1531 
1532 #ifdef MODULE
1533 module_init(mcd_init);
1534 #endif
1535 module_exit(mcd_exit);
1536 
1537 MODULE_AUTHOR("Martin Harriss");
1538 MODULE_LICENSE("GPL");
1539