1 /*
2  * The Mitsumi CDROM interface
3  * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4  * VERSION: 2.14(hs)
5  *
6  * ... anyway, I'm back again, thanks to Marcin, he adopted
7  * large portions of my code (at least the parts containing
8  * my main thoughts ...)
9  *
10  ****************** H E L P *********************************
11  * If you ever plan to update your CD ROM drive and perhaps
12  * want to sell or simply give away your Mitsumi FX-001[DS]
13  * -- Please --
14  * mail me (heiko@lotte.sax.de).  When my last drive goes
15  * ballistic no more driver support will be available from me!
16  *************************************************************
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2, or (at your option)
21  * any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; see the file COPYING.  If not, write to
30  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31  *
32  * Thanks to
33  *  The Linux Community at all and ...
34  *  Martin Harriss (he wrote the first Mitsumi Driver)
35  *  Eberhard Moenkeberg (he gave me much support and the initial kick)
36  *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
37  *      improved the original driver)
38  *  Jon Tombs, Bjorn Ekwall (module support)
39  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
40  *  Gerd Knorr (he lent me his PhotoCD)
41  *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
42  *  Andreas Kies (testing the mysterious hang-ups)
43  *  Heiko Eissfeldt (VERIFY_READ/WRITE)
44  *  Marcin Dalecki (improved performance, shortened code)
45  *  ... somebody forgotten?
46  *
47  *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x
48  *	               Removed init_module & cleanup_module in favor of
49  *		       module_init & module_exit.
50  *		       Torben Mathiasen <tmm@image.dk>
51  */
52 
53 
54 #if RCS
55 static const char *mcdx_c_version
56     = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57 #endif
58 
59 #include <linux/version.h>
60 #include <linux/module.h>
61 
62 #include <linux/errno.h>
63 #include <linux/sched.h>
64 #include <linux/fs.h>
65 #include <linux/kernel.h>
66 #include <linux/cdrom.h>
67 #include <linux/ioport.h>
68 #include <linux/mm.h>
69 #include <linux/slab.h>
70 #include <linux/init.h>
71 #include <asm/io.h>
72 #include <asm/uaccess.h>
73 
74 #include <linux/major.h>
75 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76 #include <linux/blk.h>
77 #include <linux/devfs_fs_kernel.h>
78 
79 /* for compatible parameter passing with "insmod" */
80 #define	mcdx_drive_map mcdx
81 #include "mcdx.h"
82 
83 #if BITS_PER_LONG != 32
84 #  error FIXME: this driver only works on 32-bit platforms
85 #endif
86 
87 #ifndef HZ
88 #error HZ not defined
89 #endif
90 
91 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
92 
93 #if !MCDX_QUIET
94 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
95 #else
96 #define xinfo(fmt, args...) { ; }
97 #endif
98 
99 #if MCDX_DEBUG
100 #define xtrace(lvl, fmt, args...) \
101 		{ if (lvl > 0) \
102 			{ printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
103 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
104 #else
105 #define xtrace(lvl, fmt, args...) { ; }
106 #define xdebug(fmt, args...) { ; }
107 #endif
108 
109 /* CONSTANTS *******************************************************/
110 
111 /* Following are the number of sectors we _request_ from the drive
112    every time an access outside the already requested range is done.
113    The _direct_ size is the number of sectors we're allowed to skip
114    directly (performing a read instead of requesting the new sector
115    needed */
116 const int REQUEST_SIZE = 800;	/* should be less then 255 * 4 */
117 const int DIRECT_SIZE = 400;	/* should be less then REQUEST_SIZE */
118 
119 enum drivemodes { TOC, DATA, RAW, COOKED };
120 enum datamodes { MODE0, MODE1, MODE2 };
121 enum resetmodes { SOFT, HARD };
122 
123 const int SINGLE = 0x01;	/* single speed drive (FX001S, LU) */
124 const int DOUBLE = 0x02;	/* double speed drive (FX001D, ..? */
125 const int DOOR = 0x04;		/* door locking capability */
126 const int MULTI = 0x08;		/* multi session capability */
127 
128 const unsigned char READ1X = 0xc0;
129 const unsigned char READ2X = 0xc1;
130 
131 
132 /* DECLARATIONS ****************************************************/
133 struct s_subqcode {
134 	unsigned char control;
135 	unsigned char tno;
136 	unsigned char index;
137 	struct cdrom_msf0 tt;
138 	struct cdrom_msf0 dt;
139 };
140 
141 struct s_diskinfo {
142 	unsigned int n_first;
143 	unsigned int n_last;
144 	struct cdrom_msf0 msf_leadout;
145 	struct cdrom_msf0 msf_first;
146 };
147 
148 struct s_multi {
149 	unsigned char multi;
150 	struct cdrom_msf0 msf_last;
151 };
152 
153 struct s_version {
154 	unsigned char code;
155 	unsigned char ver;
156 };
157 
158 /* Per drive/controller stuff **************************************/
159 
160 struct s_drive_stuff {
161 	/* waitqueues */
162 	wait_queue_head_t busyq;
163 	wait_queue_head_t lockq;
164 	wait_queue_head_t sleepq;
165 
166 	/* flags */
167 	volatile int introk;	/* status of last irq operation */
168 	volatile int busy;	/* drive performs an operation */
169 	volatile int lock;	/* exclusive usage */
170 
171 	/* cd infos */
172 	struct s_diskinfo di;
173 	struct s_multi multi;
174 	struct s_subqcode *toc;	/* first entry of the toc array */
175 	struct s_subqcode start;
176 	struct s_subqcode stop;
177 	int xa;			/* 1 if xa disk */
178 	int audio;		/* 1 if audio disk */
179 	int audiostatus;
180 
181 	/* `buffer' control */
182 	volatile int valid;	/* pending, ..., values are valid */
183 	volatile int pending;	/* next sector to be read */
184 	volatile int low_border;	/* first sector not to be skipped direct */
185 	volatile int high_border;	/* first sector `out of area' */
186 #ifdef AK2
187 	volatile int int_err;
188 #endif				/* AK2 */
189 
190 	/* adds and odds */
191 	void *wreg_data;	/* w data */
192 	void *wreg_reset;	/* w hardware reset */
193 	void *wreg_hcon;	/* w hardware conf */
194 	void *wreg_chn;		/* w channel */
195 	void *rreg_data;	/* r data */
196 	void *rreg_status;	/* r status */
197 
198 	int irq;		/* irq used by this drive */
199 	int minor;		/* minor number of this drive */
200 	int present;		/* drive present and its capabilities */
201 	unsigned char readcmd;	/* read cmd depends on single/double speed */
202 	unsigned char playcmd;	/* play should always be single speed */
203 	unsigned int xxx;	/* set if changed, reset while open */
204 	unsigned int yyy;	/* set if changed, reset by media_changed */
205 	int users;		/* keeps track of open/close */
206 	int lastsector;		/* last block accessible */
207 	int status;		/* last operation's error / status */
208 	int readerrs;		/* # of blocks read w/o error */
209 };
210 
211 
212 /* Prototypes ******************************************************/
213 
214 /*	The following prototypes are already declared elsewhere.  They are
215  	repeated here to show what's going on.  And to sense, if they're
216 	changed elsewhere. */
217 
218 /* declared in blk.h */
219 int mcdx_init(void);
220 void do_mcdx_request(request_queue_t * q);
221 
222 struct block_device_operations mcdx_bdops =
223 {
224 	owner:			THIS_MODULE,
225 	open:			cdrom_open,
226 	release:		cdrom_release,
227 	ioctl:			cdrom_ioctl,
228 	check_media_change:	cdrom_media_changed,
229 };
230 
231 
232 /*	Indirect exported functions. These functions are exported by their
233 	addresses, such as mcdx_open and mcdx_close in the
234 	structure mcdx_dops. */
235 
236 /* ???  exported by the mcdx_sigaction struct */
237 static void mcdx_intr(int, void *, struct pt_regs *);
238 
239 /* exported by file_ops */
240 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
241 static void mcdx_close(struct cdrom_device_info *cdi);
242 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
243 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
244 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
245 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
246 			    unsigned int cmd, void *arg);
247 
248 /* misc internal support functions */
249 static void log2msf(unsigned int, struct cdrom_msf0 *);
250 static unsigned int msf2log(const struct cdrom_msf0 *);
251 static unsigned int uint2bcd(unsigned int);
252 static unsigned int bcd2uint(unsigned char);
253 static char *port(int *);
254 static int irq(int *);
255 static void mcdx_delay(struct s_drive_stuff *, long jifs);
256 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
257 			 int nr_sectors);
258 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
259 		     int nr_sectors);
260 
261 static int mcdx_config(struct s_drive_stuff *, int);
262 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
263 			       int);
264 static int mcdx_stop(struct s_drive_stuff *, int);
265 static int mcdx_hold(struct s_drive_stuff *, int);
266 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
267 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
268 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
269 static int mcdx_requestsubqcode(struct s_drive_stuff *,
270 				struct s_subqcode *, int);
271 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
272 				     struct s_multi *, int);
273 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
274 			       int);
275 static int mcdx_getstatus(struct s_drive_stuff *, int);
276 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
277 static int mcdx_talk(struct s_drive_stuff *,
278 		     const unsigned char *cmd, size_t,
279 		     void *buffer, size_t size, unsigned int timeout, int);
280 static int mcdx_readtoc(struct s_drive_stuff *);
281 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
282 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
283 static int mcdx_setattentuator(struct s_drive_stuff *,
284 			       struct cdrom_volctrl *, int);
285 
286 /* static variables ************************************************/
287 
288 static int mcdx_blocksizes[MCDX_NDRIVES];
289 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
290 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
291 static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
292 	0, 0, 0, 0, 0, 0, 0, 0
293 };
294 MODULE_PARM(mcdx, "1-4i");
295 
296 static struct cdrom_device_ops mcdx_dops = {
297 	open:mcdx_open,
298 	release:mcdx_close,
299 	media_changed:mcdx_media_changed,
300 	tray_move:mcdx_tray_move,
301 	lock_door:mcdx_lockdoor,
302 	audio_ioctl:mcdx_audio_ioctl,
303 	capability:CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
304 	    CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
305 };
306 
307 static struct cdrom_device_info mcdx_info = {
308 	ops:&mcdx_dops,
309 	speed:2,
310 	capacity:1,
311 	name:"mcdx",
312 };
313 
314 
315 /* KERNEL INTERFACE FUNCTIONS **************************************/
316 
317 
mcdx_audio_ioctl(struct cdrom_device_info * cdi,unsigned int cmd,void * arg)318 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
319 			    unsigned int cmd, void *arg)
320 {
321 	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
322 
323 	if (!stuffp->present)
324 		return -ENXIO;
325 
326 	if (stuffp->xxx) {
327 		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
328 			stuffp->lastsector = -1;
329 		} else {
330 			stuffp->lastsector = (CD_FRAMESIZE / 512)
331 			    * msf2log(&stuffp->di.msf_leadout) - 1;
332 		}
333 
334 		if (stuffp->toc) {
335 			kfree(stuffp->toc);
336 			stuffp->toc = NULL;
337 			if (-1 == mcdx_readtoc(stuffp))
338 				return -1;
339 		}
340 
341 		stuffp->xxx = 0;
342 	}
343 
344 	switch (cmd) {
345 	case CDROMSTART:{
346 			xtrace(IOCTL, "ioctl() START\n");
347 			/* Spin up the drive.  Don't think we can do this.
348 			   * For now, ignore it.
349 			 */
350 			return 0;
351 		}
352 
353 	case CDROMSTOP:{
354 			xtrace(IOCTL, "ioctl() STOP\n");
355 			stuffp->audiostatus = CDROM_AUDIO_INVALID;
356 			if (-1 == mcdx_stop(stuffp, 1))
357 				return -EIO;
358 			return 0;
359 		}
360 
361 	case CDROMPLAYTRKIND:{
362 			struct cdrom_ti *ti = (struct cdrom_ti *) arg;
363 
364 			xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
365 			if ((ti->cdti_trk0 < stuffp->di.n_first)
366 			    || (ti->cdti_trk0 > stuffp->di.n_last)
367 			    || (ti->cdti_trk1 < stuffp->di.n_first))
368 				return -EINVAL;
369 			if (ti->cdti_trk1 > stuffp->di.n_last)
370 				ti->cdti_trk1 = stuffp->di.n_last;
371 			xtrace(PLAYTRK, "ioctl() track %d to %d\n",
372 			       ti->cdti_trk0, ti->cdti_trk1);
373 			return mcdx_playtrk(stuffp, ti);
374 		}
375 
376 	case CDROMPLAYMSF:{
377 			struct cdrom_msf *msf = (struct cdrom_msf *) arg;
378 
379 			xtrace(IOCTL, "ioctl() PLAYMSF\n");
380 
381 			if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
382 			    && (-1 == mcdx_hold(stuffp, 1)))
383 				return -EIO;
384 
385 			msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
386 			msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
387 			msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
388 
389 			msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
390 			msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
391 			msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
392 
393 			stuffp->stop.dt.minute = msf->cdmsf_min1;
394 			stuffp->stop.dt.second = msf->cdmsf_sec1;
395 			stuffp->stop.dt.frame = msf->cdmsf_frame1;
396 
397 			return mcdx_playmsf(stuffp, msf);
398 		}
399 
400 	case CDROMRESUME:{
401 			xtrace(IOCTL, "ioctl() RESUME\n");
402 			return mcdx_playtrk(stuffp, NULL);
403 		}
404 
405 	case CDROMREADTOCENTRY:{
406 			struct cdrom_tocentry *entry =
407 			    (struct cdrom_tocentry *) arg;
408 			struct s_subqcode *tp = NULL;
409 			xtrace(IOCTL, "ioctl() READTOCENTRY\n");
410 
411 			if (-1 == mcdx_readtoc(stuffp))
412 				return -1;
413 			if (entry->cdte_track == CDROM_LEADOUT)
414 				tp = &stuffp->toc[stuffp->di.n_last -
415 						  stuffp->di.n_first + 1];
416 			else if (entry->cdte_track > stuffp->di.n_last
417 				 || entry->cdte_track < stuffp->di.n_first)
418 				return -EINVAL;
419 			else
420 				tp = &stuffp->toc[entry->cdte_track -
421 						  stuffp->di.n_first];
422 
423 			if (NULL == tp)
424 				return -EIO;
425 			entry->cdte_adr = tp->control;
426 			entry->cdte_ctrl = tp->control >> 4;
427 			/* Always return stuff in MSF, and let the Uniform cdrom driver
428 			   worry about what the user actually wants */
429 			entry->cdte_addr.msf.minute =
430 			    bcd2uint(tp->dt.minute);
431 			entry->cdte_addr.msf.second =
432 			    bcd2uint(tp->dt.second);
433 			entry->cdte_addr.msf.frame =
434 			    bcd2uint(tp->dt.frame);
435 			return 0;
436 		}
437 
438 	case CDROMSUBCHNL:{
439 			struct cdrom_subchnl *sub =
440 			    (struct cdrom_subchnl *) arg;
441 			struct s_subqcode q;
442 
443 			xtrace(IOCTL, "ioctl() SUBCHNL\n");
444 
445 			if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
446 				return -EIO;
447 
448 			xtrace(SUBCHNL, "audiostatus: %x\n",
449 			       stuffp->audiostatus);
450 			sub->cdsc_audiostatus = stuffp->audiostatus;
451 			sub->cdsc_adr = q.control;
452 			sub->cdsc_ctrl = q.control >> 4;
453 			sub->cdsc_trk = bcd2uint(q.tno);
454 			sub->cdsc_ind = bcd2uint(q.index);
455 
456 			xtrace(SUBCHNL, "trk %d, ind %d\n",
457 			       sub->cdsc_trk, sub->cdsc_ind);
458 			/* Always return stuff in MSF, and let the Uniform cdrom driver
459 			   worry about what the user actually wants */
460 			sub->cdsc_absaddr.msf.minute =
461 			    bcd2uint(q.dt.minute);
462 			sub->cdsc_absaddr.msf.second =
463 			    bcd2uint(q.dt.second);
464 			sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
465 			sub->cdsc_reladdr.msf.minute =
466 			    bcd2uint(q.tt.minute);
467 			sub->cdsc_reladdr.msf.second =
468 			    bcd2uint(q.tt.second);
469 			sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
470 			xtrace(SUBCHNL,
471 			       "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
472 			       sub->cdsc_absaddr.msf.minute,
473 			       sub->cdsc_absaddr.msf.second,
474 			       sub->cdsc_absaddr.msf.frame,
475 			       sub->cdsc_reladdr.msf.minute,
476 			       sub->cdsc_reladdr.msf.second,
477 			       sub->cdsc_reladdr.msf.frame);
478 
479 			return 0;
480 		}
481 
482 	case CDROMREADTOCHDR:{
483 			struct cdrom_tochdr *toc =
484 			    (struct cdrom_tochdr *) arg;
485 
486 			xtrace(IOCTL, "ioctl() READTOCHDR\n");
487 			toc->cdth_trk0 = stuffp->di.n_first;
488 			toc->cdth_trk1 = stuffp->di.n_last;
489 			xtrace(TOCHDR,
490 			       "ioctl() track0 = %d, track1 = %d\n",
491 			       stuffp->di.n_first, stuffp->di.n_last);
492 			return 0;
493 		}
494 
495 	case CDROMPAUSE:{
496 			xtrace(IOCTL, "ioctl() PAUSE\n");
497 			if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
498 				return -EINVAL;
499 			if (-1 == mcdx_stop(stuffp, 1))
500 				return -EIO;
501 			stuffp->audiostatus = CDROM_AUDIO_PAUSED;
502 			if (-1 ==
503 			    mcdx_requestsubqcode(stuffp, &stuffp->start,
504 						 1))
505 				return -EIO;
506 			return 0;
507 		}
508 
509 	case CDROMMULTISESSION:{
510 			struct cdrom_multisession *ms =
511 			    (struct cdrom_multisession *) arg;
512 			xtrace(IOCTL, "ioctl() MULTISESSION\n");
513 			/* Always return stuff in LBA, and let the Uniform cdrom driver
514 			   worry about what the user actually wants */
515 			ms->addr.lba = msf2log(&stuffp->multi.msf_last);
516 			ms->xa_flag = !!stuffp->multi.multi;
517 			xtrace(MS,
518 			       "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
519 			       ms->xa_flag, ms->addr.lba,
520 			       stuffp->multi.msf_last.minute,
521 			       stuffp->multi.msf_last.second,
522 			       stuffp->multi.msf_last.frame);
523 
524 			return 0;
525 		}
526 
527 	case CDROMEJECT:{
528 			xtrace(IOCTL, "ioctl() EJECT\n");
529 			if (stuffp->users > 1)
530 				return -EBUSY;
531 			return (mcdx_tray_move(cdi, 1));
532 		}
533 
534 	case CDROMCLOSETRAY:{
535 			xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
536 			return (mcdx_tray_move(cdi, 0));
537 		}
538 
539 	case CDROMVOLCTRL:{
540 			struct cdrom_volctrl *volctrl =
541 			    (struct cdrom_volctrl *) arg;
542 			xtrace(IOCTL, "ioctl() VOLCTRL\n");
543 
544 #if 0				/* not tested! */
545 			/* adjust for the weirdness of workman (md) */
546 			/* can't test it (hs) */
547 			volctrl.channel2 = volctrl.channel1;
548 			volctrl.channel1 = volctrl.channel3 = 0x00;
549 #endif
550 			return mcdx_setattentuator(stuffp, volctrl, 2);
551 		}
552 
553 	default:
554 		return -EINVAL;
555 	}
556 }
557 
do_mcdx_request(request_queue_t * q)558 void do_mcdx_request(request_queue_t * q)
559 {
560 	int dev;
561 	struct s_drive_stuff *stuffp;
562 
563       again:
564 
565 	if (QUEUE_EMPTY) {
566 		xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
567 		return;
568 	}
569 
570 	if (CURRENT->rq_status == RQ_INACTIVE) {
571 		xtrace(REQUEST,
572 		       "end_request(0): rq_status == RQ_INACTIVE\n");
573 		return;
574 	}
575 
576 	INIT_REQUEST;
577 
578 	dev = MINOR(CURRENT->rq_dev);
579 	stuffp = mcdx_stuffp[dev];
580 
581 	if ((dev < 0)
582 	    || (dev >= MCDX_NDRIVES)
583 	    || !stuffp || (!stuffp->present)) {
584 		xwarn("do_request(): bad device: %s\n",
585 		      kdevname(CURRENT->rq_dev));
586 		xtrace(REQUEST, "end_request(0): bad device\n");
587 		end_request(0);
588 		return;
589 	}
590 
591 	if (stuffp->audio) {
592 		xwarn("do_request() attempt to read from audio cd\n");
593 		xtrace(REQUEST, "end_request(0): read from audio\n");
594 		end_request(0);
595 		return;
596 	}
597 
598 	xtrace(REQUEST, "do_request() (%lu + %lu)\n",
599 	       CURRENT->sector, CURRENT->nr_sectors);
600 
601 	switch (CURRENT->cmd) {
602 	case WRITE:
603 		xwarn("do_request(): attempt to write to cd!!\n");
604 		xtrace(REQUEST, "end_request(0): write\n");
605 		end_request(0);
606 		return;
607 
608 	case READ:
609 		stuffp->status = 0;
610 		while (CURRENT->nr_sectors) {
611 			int i;
612 
613 			i = mcdx_transfer(stuffp,
614 					  CURRENT->buffer,
615 					  CURRENT->sector,
616 					  CURRENT->nr_sectors);
617 
618 			if (i == -1) {
619 				end_request(0);
620 				goto again;
621 			}
622 			CURRENT->sector += i;
623 			CURRENT->nr_sectors -= i;
624 			CURRENT->buffer += (i * 512);
625 		}
626 		end_request(1);
627 		goto again;
628 
629 		xtrace(REQUEST, "end_request(1)\n");
630 		end_request(1);
631 		break;
632 
633 	default:
634 		panic(MCDX "do_request: unknown command.\n");
635 		break;
636 	}
637 
638 	goto again;
639 }
640 
mcdx_open(struct cdrom_device_info * cdi,int purpose)641 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
642 {
643 	struct s_drive_stuff *stuffp;
644 	xtrace(OPENCLOSE, "open()\n");
645 	stuffp = mcdx_stuffp[MINOR(cdi->dev)];
646 	if (!stuffp->present)
647 		return -ENXIO;
648 
649 	/* Make the modules looking used ... (thanx bjorn).
650 	 * But we shouldn't forget to decrement the module counter
651 	 * on error return */
652 
653 	/* this is only done to test if the drive talks with us */
654 	if (-1 == mcdx_getstatus(stuffp, 1))
655 		return -EIO;
656 
657 	if (stuffp->xxx) {
658 
659 		xtrace(OPENCLOSE, "open() media changed\n");
660 		stuffp->audiostatus = CDROM_AUDIO_INVALID;
661 		stuffp->readcmd = 0;
662 		xtrace(OPENCLOSE, "open() Request multisession info\n");
663 		if (-1 ==
664 		    mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
665 			xinfo("No multidiskinfo\n");
666 	} else {
667 		/* multisession ? */
668 		if (!stuffp->multi.multi)
669 			stuffp->multi.msf_last.second = 2;
670 
671 		xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
672 		       stuffp->multi.multi,
673 		       stuffp->multi.msf_last.minute,
674 		       stuffp->multi.msf_last.second,
675 		       stuffp->multi.msf_last.frame);
676 
677 		{;
678 		}		/* got multisession information */
679 		/* request the disks table of contents (aka diskinfo) */
680 		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
681 
682 			stuffp->lastsector = -1;
683 
684 		} else {
685 
686 			stuffp->lastsector = (CD_FRAMESIZE / 512)
687 			    * msf2log(&stuffp->di.msf_leadout) - 1;
688 
689 			xtrace(OPENCLOSE,
690 			       "open() start %d (%02x:%02x.%02x) %d\n",
691 			       stuffp->di.n_first,
692 			       stuffp->di.msf_first.minute,
693 			       stuffp->di.msf_first.second,
694 			       stuffp->di.msf_first.frame,
695 			       msf2log(&stuffp->di.msf_first));
696 			xtrace(OPENCLOSE,
697 			       "open() last %d (%02x:%02x.%02x) %d\n",
698 			       stuffp->di.n_last,
699 			       stuffp->di.msf_leadout.minute,
700 			       stuffp->di.msf_leadout.second,
701 			       stuffp->di.msf_leadout.frame,
702 			       msf2log(&stuffp->di.msf_leadout));
703 		}
704 
705 		if (stuffp->toc) {
706 			xtrace(MALLOC, "open() free old toc @ %p\n",
707 			       stuffp->toc);
708 			kfree(stuffp->toc);
709 
710 			stuffp->toc = NULL;
711 		}
712 
713 		xtrace(OPENCLOSE, "open() init irq generation\n");
714 		if (-1 == mcdx_config(stuffp, 1))
715 			return -EIO;
716 #if FALLBACK
717 		/* Set the read speed */
718 		xwarn("AAA %x AAA\n", stuffp->readcmd);
719 		if (stuffp->readerrs)
720 			stuffp->readcmd = READ1X;
721 		else
722 			stuffp->readcmd =
723 			    stuffp->present | SINGLE ? READ1X : READ2X;
724 		xwarn("XXX %x XXX\n", stuffp->readcmd);
725 #else
726 		stuffp->readcmd =
727 		    stuffp->present | SINGLE ? READ1X : READ2X;
728 #endif
729 
730 		/* try to get the first sector, iff any ... */
731 		if (stuffp->lastsector >= 0) {
732 			char buf[512];
733 			int ans;
734 			int tries;
735 
736 			stuffp->xa = 0;
737 			stuffp->audio = 0;
738 
739 			for (tries = 6; tries; tries--) {
740 
741 				stuffp->introk = 1;
742 
743 				xtrace(OPENCLOSE, "open() try as %s\n",
744 				       stuffp->xa ? "XA" : "normal");
745 				/* set data mode */
746 				if (-1 == (ans = mcdx_setdatamode(stuffp,
747 								  stuffp->
748 								  xa ?
749 								  MODE2 :
750 								  MODE1,
751 								  1))) {
752 					/* return -EIO; */
753 					stuffp->xa = 0;
754 					break;
755 				}
756 
757 				if ((stuffp->audio = e_audio(ans)))
758 					break;
759 
760 				while (0 ==
761 				       (ans =
762 					mcdx_transfer(stuffp, buf, 0, 1)));
763 
764 				if (ans == 1)
765 					break;
766 				stuffp->xa = !stuffp->xa;
767 			}
768 		}
769 		/* xa disks will be read in raw mode, others not */
770 		if (-1 == mcdx_setdrivemode(stuffp,
771 					    stuffp->xa ? RAW : COOKED,
772 					    1))
773 			return -EIO;
774 		if (stuffp->audio) {
775 			xinfo("open() audio disk found\n");
776 		} else if (stuffp->lastsector >= 0) {
777 			xinfo("open() %s%s disk found\n",
778 			      stuffp->xa ? "XA / " : "",
779 			      stuffp->multi.
780 			      multi ? "Multi Session" : "Single Session");
781 		}
782 	}
783 	stuffp->xxx = 0;
784 	stuffp->users++;
785 	return 0;
786 }
787 
mcdx_close(struct cdrom_device_info * cdi)788 static void mcdx_close(struct cdrom_device_info *cdi)
789 {
790 	struct s_drive_stuff *stuffp;
791 
792 	xtrace(OPENCLOSE, "close()\n");
793 
794 	stuffp = mcdx_stuffp[MINOR(cdi->dev)];
795 
796 	--stuffp->users;
797 }
798 
mcdx_media_changed(struct cdrom_device_info * cdi,int disc_nr)799 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
800 /*	Return: 1 if media changed since last call to this function
801 			0 otherwise */
802 {
803 	struct s_drive_stuff *stuffp;
804 
805 	xinfo("mcdx_media_changed called for device %s\n",
806 	      kdevname(cdi->dev));
807 
808 	stuffp = mcdx_stuffp[MINOR(cdi->dev)];
809 	mcdx_getstatus(stuffp, 1);
810 
811 	if (stuffp->yyy == 0)
812 		return 0;
813 
814 	stuffp->yyy = 0;
815 	return 1;
816 }
817 
818 #ifndef MODULE
mcdx_setup(char * str)819 static int __init mcdx_setup(char *str)
820 {
821 	int pi[4];
822 	(void) get_options(str, ARRAY_SIZE(pi), pi);
823 
824 	if (pi[0] > 0)
825 		mcdx_drive_map[0][0] = pi[1];
826 	if (pi[0] > 1)
827 		mcdx_drive_map[0][1] = pi[2];
828 	return 1;
829 }
830 
831 __setup("mcdx=", mcdx_setup);
832 
833 #endif
834 
835 /* DIRTY PART ******************************************************/
836 
mcdx_delay(struct s_drive_stuff * stuff,long jifs)837 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
838 /* This routine is used for sleeping.
839  * A jifs value <0 means NO sleeping,
840  *              =0 means minimal sleeping (let the kernel
841  *                 run for other processes)
842  *              >0 means at least sleep for that amount.
843  *	May be we could use a simple count loop w/ jumps to itself, but
844  *	I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
845 {
846 	if (jifs < 0)
847 		return;
848 
849 	xtrace(SLEEP, "*** delay: sleepq\n");
850 	interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
851 	xtrace(SLEEP, "delay awoken\n");
852 	if (signal_pending(current)) {
853 		xtrace(SLEEP, "got signal\n");
854 	}
855 }
856 
mcdx_intr(int irq,void * dev_id,struct pt_regs * regs)857 static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
858 {
859 	struct s_drive_stuff *stuffp;
860 	unsigned char b;
861 
862 	stuffp = mcdx_irq_map[irq];
863 
864 	if (stuffp == NULL) {
865 		xwarn("mcdx: no device for intr %d\n", irq);
866 		return;
867 	}
868 #ifdef AK2
869 	if (!stuffp->busy && stuffp->pending)
870 		stuffp->int_err = 1;
871 
872 #endif				/* AK2 */
873 	/* get the interrupt status */
874 	b = inb((unsigned int) stuffp->rreg_status);
875 	stuffp->introk = ~b & MCDX_RBIT_DTEN;
876 
877 	/* NOTE: We only should get interrupts if the data we
878 	 * requested are ready to transfer.
879 	 * But the drive seems to generate ``asynchronous'' interrupts
880 	 * on several error conditions too.  (Despite the err int enable
881 	 * setting during initialisation) */
882 
883 	/* if not ok, read the next byte as the drives status */
884 	if (!stuffp->introk) {
885 		xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
886 		if (~b & MCDX_RBIT_STEN) {
887 			xinfo("intr() irq %d    status 0x%02x\n",
888 			      irq, inb((unsigned int) stuffp->rreg_data));
889 		} else {
890 			xinfo("intr() irq %d ambiguous hw status\n", irq);
891 		}
892 	} else {
893 		xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
894 	}
895 
896 	stuffp->busy = 0;
897 	wake_up_interruptible(&stuffp->busyq);
898 }
899 
900 
mcdx_talk(struct s_drive_stuff * stuffp,const unsigned char * cmd,size_t cmdlen,void * buffer,size_t size,unsigned int timeout,int tries)901 static int mcdx_talk(struct s_drive_stuff *stuffp,
902 	  const unsigned char *cmd, size_t cmdlen,
903 	  void *buffer, size_t size, unsigned int timeout, int tries)
904 /* Send a command to the drive, wait for the result.
905  * returns -1 on timeout, drive status otherwise
906  * If buffer is not zero, the result (length size) is stored there.
907  * If buffer is zero the size should be the number of bytes to read
908  * from the drive.  These bytes are discarded.
909  */
910 {
911 	int st;
912 	char c;
913 	int discard;
914 
915 	/* Somebody wants the data read? */
916 	if ((discard = (buffer == NULL)))
917 		buffer = &c;
918 
919 	while (stuffp->lock) {
920 		xtrace(SLEEP, "*** talk: lockq\n");
921 		interruptible_sleep_on(&stuffp->lockq);
922 		xtrace(SLEEP, "talk: awoken\n");
923 	}
924 
925 	stuffp->lock = 1;
926 
927 	/* An operation other then reading data destroys the
928 	   * data already requested and remembered in stuffp->request, ... */
929 	stuffp->valid = 0;
930 
931 #if MCDX_DEBUG & TALK
932 	{
933 		unsigned char i;
934 		xtrace(TALK,
935 		       "talk() %d / %d tries, res.size %d, command 0x%02x",
936 		       tries, timeout, size, (unsigned char) cmd[0]);
937 		for (i = 1; i < cmdlen; i++)
938 			xtrace(TALK, " 0x%02x", cmd[i]);
939 		xtrace(TALK, "\n");
940 	}
941 #endif
942 
943 	/*  give up if all tries are done (bad) or if the status
944 	 *  st != -1 (good) */
945 	for (st = -1; st == -1 && tries; tries--) {
946 
947 		char *bp = (char *) buffer;
948 		size_t sz = size;
949 
950 		outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
951 		xtrace(TALK, "talk() command sent\n");
952 
953 		/* get the status byte */
954 		if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
955 			xinfo("talk() %02x timed out (status), %d tr%s left\n",
956 			     cmd[0], tries - 1, tries == 2 ? "y" : "ies");
957 			continue;
958 		}
959 		st = *bp;
960 		sz--;
961 		if (!discard)
962 			bp++;
963 
964 		xtrace(TALK, "talk() got status 0x%02x\n", st);
965 
966 		/* command error? */
967 		if (e_cmderr(st)) {
968 			xwarn("command error cmd = %02x %s \n",
969 			      cmd[0], cmdlen > 1 ? "..." : "");
970 			st = -1;
971 			continue;
972 		}
973 
974 		/* audio status? */
975 		if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
976 			stuffp->audiostatus =
977 			    e_audiobusy(st) ? CDROM_AUDIO_PLAY :
978 			    CDROM_AUDIO_NO_STATUS;
979 		else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
980 			 && e_audiobusy(st) == 0)
981 			stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
982 
983 		/* media change? */
984 		if (e_changed(st)) {
985 			xinfo("talk() media changed\n");
986 			stuffp->xxx = stuffp->yyy = 1;
987 		}
988 
989 		/* now actually get the data */
990 		while (sz--) {
991 			if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
992 				xinfo("talk() %02x timed out (data), %d tr%s left\n",
993 				     cmd[0], tries - 1,
994 				     tries == 2 ? "y" : "ies");
995 				st = -1;
996 				break;
997 			}
998 			if (!discard)
999 				bp++;
1000 			xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
1001 		}
1002 	}
1003 
1004 #if !MCDX_QUIET
1005 	if (!tries && st == -1)
1006 		xinfo("talk() giving up\n");
1007 #endif
1008 
1009 	stuffp->lock = 0;
1010 	wake_up_interruptible(&stuffp->lockq);
1011 
1012 	xtrace(TALK, "talk() done with 0x%02x\n", st);
1013 	return st;
1014 }
1015 
1016 /* MODULE STUFF ***********************************************************/
1017 
1018 EXPORT_NO_SYMBOLS;
1019 
__mcdx_init(void)1020 int __mcdx_init(void)
1021 {
1022 	int i;
1023 	int drives = 0;
1024 
1025 	mcdx_init();
1026 	for (i = 0; i < MCDX_NDRIVES; i++) {
1027 		if (mcdx_stuffp[i]) {
1028 			xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1029 			       i, mcdx_stuffp[i]);
1030 			drives++;
1031 		}
1032 	}
1033 
1034 	if (!drives)
1035 		return -EIO;
1036 
1037 	return 0;
1038 }
1039 
mcdx_exit(void)1040 void __exit mcdx_exit(void)
1041 {
1042 	int i;
1043 
1044 	xinfo("cleanup_module called\n");
1045 
1046 	for (i = 0; i < MCDX_NDRIVES; i++) {
1047 		struct s_drive_stuff *stuffp;
1048 		if (unregister_cdrom(&mcdx_info)) {
1049 			printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1050 			return;
1051 		}
1052 		stuffp = mcdx_stuffp[i];
1053 		if (!stuffp)
1054 			continue;
1055 		release_region((unsigned long) stuffp->wreg_data,
1056 			       MCDX_IO_SIZE);
1057 		free_irq(stuffp->irq, NULL);
1058 		if (stuffp->toc) {
1059 			xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1060 			       stuffp->toc);
1061 			kfree(stuffp->toc);
1062 		}
1063 		xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1064 		       stuffp);
1065 		mcdx_stuffp[i] = NULL;
1066 		kfree(stuffp);
1067 	}
1068 
1069 	if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1070 		xwarn("cleanup() unregister_blkdev() failed\n");
1071 	}
1072 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1073 #if !MCDX_QUIET
1074 	else
1075 	xinfo("cleanup() succeeded\n");
1076 #endif
1077 }
1078 
1079 #ifdef MODULE
1080 module_init(__mcdx_init);
1081 #endif
1082 module_exit(mcdx_exit);
1083 
1084 
1085 /* Support functions ************************************************/
1086 
mcdx_init_drive(int drive)1087 int __init mcdx_init_drive(int drive)
1088 {
1089 	struct s_version version;
1090 	struct s_drive_stuff *stuffp;
1091 	int size = sizeof(*stuffp);
1092 	char msg[80];
1093 
1094 	mcdx_blocksizes[drive] = 0;
1095 
1096 	xtrace(INIT, "init() try drive %d\n", drive);
1097 
1098 	xtrace(INIT, "kmalloc space for stuffpt's\n");
1099 	xtrace(MALLOC, "init() malloc %d bytes\n", size);
1100 	if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1101 		xwarn("init() malloc failed\n");
1102 		return 1;
1103 	}
1104 
1105 	xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1106 	       sizeof(*stuffp), stuffp);
1107 
1108 	/* set default values */
1109 	memset(stuffp, 0, sizeof(*stuffp));
1110 
1111 	stuffp->present = 0;	/* this should be 0 already */
1112 	stuffp->toc = NULL;	/* this should be NULL already */
1113 
1114 	/* setup our irq and i/o addresses */
1115 	stuffp->irq = irq(mcdx_drive_map[drive]);
1116 	stuffp->wreg_data = stuffp->rreg_data =
1117 	    port(mcdx_drive_map[drive]);
1118 	stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1119 	stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1120 	stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1121 
1122 	init_waitqueue_head(&stuffp->busyq);
1123 	init_waitqueue_head(&stuffp->lockq);
1124 	init_waitqueue_head(&stuffp->sleepq);
1125 
1126 	/* check if i/o addresses are available */
1127 	if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1128 		xwarn("0x%3p,%d: Init failed. "
1129 		      "I/O ports (0x%3p..0x%3p) already in use.\n",
1130 		      stuffp->wreg_data, stuffp->irq,
1131 		      stuffp->wreg_data,
1132 		      stuffp->wreg_data + MCDX_IO_SIZE - 1);
1133 		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1134 		kfree(stuffp);
1135 		xtrace(INIT, "init() continue at next drive\n");
1136 		return 0;	/* next drive */
1137 	}
1138 
1139 	xtrace(INIT, "init() i/o port is available at 0x%3p\n",
1140 	       stuffp->wreg_data);
1141 	xtrace(INIT, "init() hardware reset\n");
1142 	mcdx_reset(stuffp, HARD, 1);
1143 
1144 	xtrace(INIT, "init() get version\n");
1145 	if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1146 		/* failed, next drive */
1147 		xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1148 		      MCDX, stuffp->wreg_data, stuffp->irq);
1149 		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1150 		kfree(stuffp);
1151 		xtrace(INIT, "init() continue at next drive\n");
1152 		return 0;
1153 	}
1154 
1155 	switch (version.code) {
1156 	case 'D':
1157 		stuffp->readcmd = READ2X;
1158 		stuffp->present = DOUBLE | DOOR | MULTI;
1159 		break;
1160 	case 'F':
1161 		stuffp->readcmd = READ1X;
1162 		stuffp->present = SINGLE | DOOR | MULTI;
1163 		break;
1164 	case 'M':
1165 		stuffp->readcmd = READ1X;
1166 		stuffp->present = SINGLE;
1167 		break;
1168 	default:
1169 		stuffp->present = 0;
1170 		break;
1171 	}
1172 
1173 	stuffp->playcmd = READ1X;
1174 
1175 	if (!stuffp->present) {
1176 		xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1177 		      MCDX, stuffp->wreg_data, stuffp->irq);
1178 		kfree(stuffp);
1179 		return 0;	/* next drive */
1180 	}
1181 
1182 	xtrace(INIT, "init() register blkdev\n");
1183 	if (devfs_register_blkdev(MAJOR_NR, "mcdx", &mcdx_bdops) != 0) {
1184 		xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1185 		      MCDX, stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1186 		kfree(stuffp);
1187 		return 1;
1188 	}
1189 
1190 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1191 	read_ahead[MAJOR_NR] = READ_AHEAD;
1192 	blksize_size[MAJOR_NR] = mcdx_blocksizes;
1193 
1194 	xtrace(INIT, "init() subscribe irq and i/o\n");
1195 	mcdx_irq_map[stuffp->irq] = stuffp;
1196 	if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1197 		xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1198 		      MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1199 		stuffp->irq = 0;
1200 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1201 		kfree(stuffp);
1202 		return 0;
1203 	}
1204 	request_region((unsigned int) stuffp->wreg_data,
1205 		       MCDX_IO_SIZE, "mcdx");
1206 
1207 	xtrace(INIT, "init() get garbage\n");
1208 	{
1209 		int i;
1210 		mcdx_delay(stuffp, HZ / 2);
1211 		for (i = 100; i; i--)
1212 			(void) inb((unsigned int) stuffp->rreg_status);
1213 	}
1214 
1215 
1216 #if WE_KNOW_WHY
1217 	/* irq 11 -> channel register */
1218 	outb(0x50, (unsigned int) stuffp->wreg_chn);
1219 #endif
1220 
1221 	xtrace(INIT, "init() set non dma but irq mode\n");
1222 	mcdx_config(stuffp, 1);
1223 
1224 	stuffp->minor = drive;
1225 
1226 	sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1227 		" (Firmware version %c %x)\n",
1228 		stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1229 	mcdx_stuffp[drive] = stuffp;
1230 	xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1231 	mcdx_info.dev = MKDEV(MAJOR_NR, 0);
1232 	if (register_cdrom(&mcdx_info) != 0) {
1233 		printk("Cannot register Mitsumi CD-ROM!\n");
1234 		release_region((unsigned long) stuffp->wreg_data,
1235 			       MCDX_IO_SIZE);
1236 		free_irq(stuffp->irq, NULL);
1237 		kfree(stuffp);
1238 		if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1239 			xwarn("cleanup() unregister_blkdev() failed\n");
1240 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1241 		return 2;
1242 	}
1243 	devfs_plain_cdrom(&mcdx_info, &mcdx_bdops);
1244 	printk(msg);
1245 	return 0;
1246 }
1247 
mcdx_init(void)1248 int __init mcdx_init(void)
1249 {
1250 	int drive;
1251 #ifdef MODULE
1252 	xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1253 #else
1254 	xwarn("Version 2.14(hs) \n");
1255 #endif
1256 
1257 	xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1258 
1259 	/* zero the pointer array */
1260 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
1261 		mcdx_stuffp[drive] = NULL;
1262 
1263 	/* do the initialisation */
1264 	for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1265 		switch (mcdx_init_drive(drive)) {
1266 		case 2:
1267 			return -EIO;
1268 		case 1:
1269 			break;
1270 		}
1271 	}
1272 	return 0;
1273 }
1274 
mcdx_transfer(struct s_drive_stuff * stuffp,char * p,int sector,int nr_sectors)1275 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1276 	      char *p, int sector, int nr_sectors)
1277 /*	This seems to do the actually transfer.  But it does more.  It
1278 	keeps track of errors occurred and will (if possible) fall back
1279 	to single speed on error.
1280 	Return:	-1 on timeout or other error
1281 			else status byte (as in stuff->st) */
1282 {
1283 	int ans;
1284 
1285 	ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1286 	return ans;
1287 #if FALLBACK
1288 	if (-1 == ans)
1289 		stuffp->readerrs++;
1290 	else
1291 		return ans;
1292 
1293 	if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1294 		xwarn("XXX Already reading 1x -- no chance\n");
1295 		return -1;
1296 	}
1297 
1298 	xwarn("XXX Fallback to 1x\n");
1299 
1300 	stuffp->readcmd = READ1X;
1301 	return mcdx_transfer(stuffp, p, sector, nr_sectors);
1302 #endif
1303 
1304 }
1305 
1306 
mcdx_xfer(struct s_drive_stuff * stuffp,char * p,int sector,int nr_sectors)1307 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1308 		     char *p, int sector, int nr_sectors)
1309 /*	This does actually the transfer from the drive.
1310 	Return:	-1 on timeout or other error
1311 			else status byte (as in stuff->st) */
1312 {
1313 	int border;
1314 	int done = 0;
1315 	long timeout;
1316 
1317 	if (stuffp->audio) {
1318 		xwarn("Attempt to read from audio CD.\n");
1319 		return -1;
1320 	}
1321 
1322 	if (!stuffp->readcmd) {
1323 		xinfo("Can't transfer from missing disk.\n");
1324 		return -1;
1325 	}
1326 
1327 	while (stuffp->lock) {
1328 		interruptible_sleep_on(&stuffp->lockq);
1329 	}
1330 
1331 	if (stuffp->valid && (sector >= stuffp->pending)
1332 	    && (sector < stuffp->low_border)) {
1333 
1334 		/* All (or at least a part of the sectors requested) seems
1335 		   * to be already requested, so we don't need to bother the
1336 		   * drive with new requests ...
1337 		   * Wait for the drive become idle, but first
1338 		   * check for possible occurred errors --- the drive
1339 		   * seems to report them asynchronously */
1340 
1341 
1342 		border = stuffp->high_border < (border =
1343 						sector + nr_sectors)
1344 		    ? stuffp->high_border : border;
1345 
1346 		stuffp->lock = current->pid;
1347 
1348 		do {
1349 
1350 			while (stuffp->busy) {
1351 
1352 				timeout =
1353 				    interruptible_sleep_on_timeout
1354 				    (&stuffp->busyq, 5 * HZ);
1355 
1356 				if (!stuffp->introk) {
1357 					xtrace(XFER,
1358 					       "error via interrupt\n");
1359 				} else if (!timeout) {
1360 					xtrace(XFER, "timeout\n");
1361 				} else if (signal_pending(current)) {
1362 					xtrace(XFER, "signal\n");
1363 				} else
1364 					continue;
1365 
1366 				stuffp->lock = 0;
1367 				stuffp->busy = 0;
1368 				stuffp->valid = 0;
1369 
1370 				wake_up_interruptible(&stuffp->lockq);
1371 				xtrace(XFER, "transfer() done (-1)\n");
1372 				return -1;
1373 			}
1374 
1375 			/* check if we need to set the busy flag (as we
1376 			 * expect an interrupt */
1377 			stuffp->busy = (3 == (stuffp->pending & 3));
1378 
1379 			/* Test if it's the first sector of a block,
1380 			 * there we have to skip some bytes as we read raw data */
1381 			if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1382 				const int HEAD =
1383 				    CD_FRAMESIZE_RAW - CD_XA_TAIL -
1384 				    CD_FRAMESIZE;
1385 				insb((unsigned int) stuffp->rreg_data, p,
1386 				     HEAD);
1387 			}
1388 
1389 			/* now actually read the data */
1390 			insb((unsigned int) stuffp->rreg_data, p, 512);
1391 
1392 			/* test if it's the last sector of a block,
1393 			 * if so, we have to handle XA special */
1394 			if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1395 				char dummy[CD_XA_TAIL];
1396 				insb((unsigned int) stuffp->rreg_data,
1397 				     &dummy[0], CD_XA_TAIL);
1398 			}
1399 
1400 			if (stuffp->pending == sector) {
1401 				p += 512;
1402 				done++;
1403 				sector++;
1404 			}
1405 		} while (++(stuffp->pending) < border);
1406 
1407 		stuffp->lock = 0;
1408 		wake_up_interruptible(&stuffp->lockq);
1409 
1410 	} else {
1411 
1412 		/* The requested sector(s) is/are out of the
1413 		 * already requested range, so we have to bother the drive
1414 		 * with a new request. */
1415 
1416 		static unsigned char cmd[] = {
1417 			0,
1418 			0, 0, 0,
1419 			0, 0, 0
1420 		};
1421 
1422 		cmd[0] = stuffp->readcmd;
1423 
1424 		/* The numbers held in ->pending, ..., should be valid */
1425 		stuffp->valid = 1;
1426 		stuffp->pending = sector & ~3;
1427 
1428 		/* do some sanity checks */
1429 		if (stuffp->pending > stuffp->lastsector) {
1430 			xwarn
1431 			    ("transfer() sector %d from nirvana requested.\n",
1432 			     stuffp->pending);
1433 			stuffp->status = MCDX_ST_EOM;
1434 			stuffp->valid = 0;
1435 			xtrace(XFER, "transfer() done (-1)\n");
1436 			return -1;
1437 		}
1438 
1439 		if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1440 		    > stuffp->lastsector + 1) {
1441 			xtrace(XFER, "cut low_border\n");
1442 			stuffp->low_border = stuffp->lastsector + 1;
1443 		}
1444 		if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1445 		    > stuffp->lastsector + 1) {
1446 			xtrace(XFER, "cut high_border\n");
1447 			stuffp->high_border = stuffp->lastsector + 1;
1448 		}
1449 
1450 		{		/* Convert the sector to be requested to MSF format */
1451 			struct cdrom_msf0 pending;
1452 			log2msf(stuffp->pending / 4, &pending);
1453 			cmd[1] = pending.minute;
1454 			cmd[2] = pending.second;
1455 			cmd[3] = pending.frame;
1456 		}
1457 
1458 		cmd[6] =
1459 		    (unsigned
1460 		     char) ((stuffp->high_border - stuffp->pending) / 4);
1461 		xtrace(XFER, "[%2d]\n", cmd[6]);
1462 
1463 		stuffp->busy = 1;
1464 		/* Now really issue the request command */
1465 		outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1466 
1467 	}
1468 #ifdef AK2
1469 	if (stuffp->int_err) {
1470 		stuffp->valid = 0;
1471 		stuffp->int_err = 0;
1472 		return -1;
1473 	}
1474 #endif				/* AK2 */
1475 
1476 	stuffp->low_border = (stuffp->low_border +=
1477 			      done) <
1478 	    stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1479 
1480 	return done;
1481 }
1482 
1483 
1484 /*	Access to elements of the mcdx_drive_map members */
1485 
port(int * ip)1486 static char *port(int *ip)
1487 {
1488 	return (char *) ip[0];
1489 }
irq(int * ip)1490 static int irq(int *ip)
1491 {
1492 	return ip[1];
1493 }
1494 
1495 /*	Misc number converters */
1496 
bcd2uint(unsigned char c)1497 static unsigned int bcd2uint(unsigned char c)
1498 {
1499 	return (c >> 4) * 10 + (c & 0x0f);
1500 }
1501 
uint2bcd(unsigned int ival)1502 static unsigned int uint2bcd(unsigned int ival)
1503 {
1504 	return ((ival / 10) << 4) | (ival % 10);
1505 }
1506 
log2msf(unsigned int l,struct cdrom_msf0 * pmsf)1507 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1508 {
1509 	l += CD_MSF_OFFSET;
1510 	pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1511 	pmsf->second = uint2bcd(l / 75);
1512 	pmsf->frame = uint2bcd(l % 75);
1513 }
1514 
msf2log(const struct cdrom_msf0 * pmsf)1515 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1516 {
1517 	return bcd2uint(pmsf->frame)
1518 	    + bcd2uint(pmsf->second) * 75
1519 	    + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1520 }
1521 
mcdx_readtoc(struct s_drive_stuff * stuffp)1522 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1523 /*  Read the toc entries from the CD,
1524  *  Return: -1 on failure, else 0 */
1525 {
1526 
1527 	if (stuffp->toc) {
1528 		xtrace(READTOC, "ioctl() toc already read\n");
1529 		return 0;
1530 	}
1531 
1532 	xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1533 	       stuffp->di.n_last - stuffp->di.n_first + 1);
1534 
1535 	if (-1 == mcdx_hold(stuffp, 1))
1536 		return -1;
1537 
1538 	xtrace(READTOC, "ioctl() tocmode\n");
1539 	if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1540 		return -EIO;
1541 
1542 	/* all seems to be ok so far ... malloc */
1543 	{
1544 		int size;
1545 		size =
1546 		    sizeof(struct s_subqcode) * (stuffp->di.n_last -
1547 						 stuffp->di.n_first + 2);
1548 
1549 		xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1550 		stuffp->toc = kmalloc(size, GFP_KERNEL);
1551 		if (!stuffp->toc) {
1552 			xwarn("Cannot malloc %d bytes for toc\n", size);
1553 			mcdx_setdrivemode(stuffp, DATA, 1);
1554 			return -EIO;
1555 		}
1556 	}
1557 
1558 	/* now read actually the index */
1559 	{
1560 		int trk;
1561 		int retries;
1562 
1563 		for (trk = 0;
1564 		     trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1565 		     trk++)
1566 			stuffp->toc[trk].index = 0;
1567 
1568 		for (retries = 300; retries; retries--) {	/* why 300? */
1569 			struct s_subqcode q;
1570 			unsigned int idx;
1571 
1572 			if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1573 				mcdx_setdrivemode(stuffp, DATA, 1);
1574 				return -EIO;
1575 			}
1576 
1577 			idx = bcd2uint(q.index);
1578 
1579 			if ((idx > 0)
1580 			    && (idx <= stuffp->di.n_last)
1581 			    && (q.tno == 0)
1582 			    && (stuffp->toc[idx - stuffp->di.n_first].
1583 				index == 0)) {
1584 				stuffp->toc[idx - stuffp->di.n_first] = q;
1585 				xtrace(READTOC,
1586 				       "ioctl() toc idx %d (trk %d)\n",
1587 				       idx, trk);
1588 				trk--;
1589 			}
1590 			if (trk == 0)
1591 				break;
1592 		}
1593 		memset(&stuffp->
1594 		       toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1595 		       sizeof(stuffp->toc[0]));
1596 		stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1597 			    1].dt = stuffp->di.msf_leadout;
1598 	}
1599 
1600 	/* unset toc mode */
1601 	xtrace(READTOC, "ioctl() undo toc mode\n");
1602 	if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1603 		return -EIO;
1604 
1605 #if MCDX_DEBUG && READTOC
1606 	{
1607 		int trk;
1608 		for (trk = 0;
1609 		     trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1610 		     trk++)
1611 			xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1612 			       "  %02x:%02x.%02x  %02x:%02x.%02x\n",
1613 			       trk + stuffp->di.n_first,
1614 			       stuffp->toc[trk].control,
1615 			       stuffp->toc[trk].tno,
1616 			       stuffp->toc[trk].index,
1617 			       stuffp->toc[trk].tt.minute,
1618 			       stuffp->toc[trk].tt.second,
1619 			       stuffp->toc[trk].tt.frame,
1620 			       stuffp->toc[trk].dt.minute,
1621 			       stuffp->toc[trk].dt.second,
1622 			       stuffp->toc[trk].dt.frame);
1623 	}
1624 #endif
1625 
1626 	return 0;
1627 }
1628 
1629 static int
mcdx_playmsf(struct s_drive_stuff * stuffp,const struct cdrom_msf * msf)1630 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1631 {
1632 	unsigned char cmd[7] = {
1633 		0, 0, 0, 0, 0, 0, 0
1634 	};
1635 
1636 	if (!stuffp->readcmd) {
1637 		xinfo("Can't play from missing disk.\n");
1638 		return -1;
1639 	}
1640 
1641 	cmd[0] = stuffp->playcmd;
1642 
1643 	cmd[1] = msf->cdmsf_min0;
1644 	cmd[2] = msf->cdmsf_sec0;
1645 	cmd[3] = msf->cdmsf_frame0;
1646 	cmd[4] = msf->cdmsf_min1;
1647 	cmd[5] = msf->cdmsf_sec1;
1648 	cmd[6] = msf->cdmsf_frame1;
1649 
1650 	xtrace(PLAYMSF, "ioctl(): play %x "
1651 	       "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1652 	       cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1653 
1654 	outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1655 
1656 	if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1657 		xwarn("playmsf() timeout\n");
1658 		return -1;
1659 	}
1660 
1661 	stuffp->audiostatus = CDROM_AUDIO_PLAY;
1662 	return 0;
1663 }
1664 
1665 static int
mcdx_playtrk(struct s_drive_stuff * stuffp,const struct cdrom_ti * ti)1666 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1667 {
1668 	struct s_subqcode *p;
1669 	struct cdrom_msf msf;
1670 
1671 	if (-1 == mcdx_readtoc(stuffp))
1672 		return -1;
1673 
1674 	if (ti)
1675 		p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1676 	else
1677 		p = &stuffp->start;
1678 
1679 	msf.cdmsf_min0 = p->dt.minute;
1680 	msf.cdmsf_sec0 = p->dt.second;
1681 	msf.cdmsf_frame0 = p->dt.frame;
1682 
1683 	if (ti) {
1684 		p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1685 		stuffp->stop = *p;
1686 	} else
1687 		p = &stuffp->stop;
1688 
1689 	msf.cdmsf_min1 = p->dt.minute;
1690 	msf.cdmsf_sec1 = p->dt.second;
1691 	msf.cdmsf_frame1 = p->dt.frame;
1692 
1693 	return mcdx_playmsf(stuffp, &msf);
1694 }
1695 
1696 
1697 /* Drive functions ************************************************/
1698 
mcdx_tray_move(struct cdrom_device_info * cdi,int position)1699 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1700 {
1701 	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1702 
1703 	if (!stuffp->present)
1704 		return -ENXIO;
1705 	if (!(stuffp->present & DOOR))
1706 		return -ENOSYS;
1707 
1708 	if (position)		/* 1: eject */
1709 		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1710 	else			/* 0: close */
1711 		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1712 	return 1;
1713 }
1714 
mcdx_stop(struct s_drive_stuff * stuffp,int tries)1715 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1716 {
1717 	return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1718 }
1719 
mcdx_hold(struct s_drive_stuff * stuffp,int tries)1720 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1721 {
1722 	return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1723 }
1724 
mcdx_requestsubqcode(struct s_drive_stuff * stuffp,struct s_subqcode * sub,int tries)1725 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1726 		     struct s_subqcode *sub, int tries)
1727 {
1728 	char buf[11];
1729 	int ans;
1730 
1731 	if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1732 				   2 * HZ, tries)))
1733 		return -1;
1734 	sub->control = buf[1];
1735 	sub->tno = buf[2];
1736 	sub->index = buf[3];
1737 	sub->tt.minute = buf[4];
1738 	sub->tt.second = buf[5];
1739 	sub->tt.frame = buf[6];
1740 	sub->dt.minute = buf[8];
1741 	sub->dt.second = buf[9];
1742 	sub->dt.frame = buf[10];
1743 
1744 	return ans;
1745 }
1746 
mcdx_requestmultidiskinfo(struct s_drive_stuff * stuffp,struct s_multi * multi,int tries)1747 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1748 			  struct s_multi *multi, int tries)
1749 {
1750 	char buf[5];
1751 	int ans;
1752 
1753 	if (stuffp->present & MULTI) {
1754 		ans =
1755 		    mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1756 			      tries);
1757 		multi->multi = buf[1];
1758 		multi->msf_last.minute = buf[2];
1759 		multi->msf_last.second = buf[3];
1760 		multi->msf_last.frame = buf[4];
1761 		return ans;
1762 	} else {
1763 		multi->multi = 0;
1764 		return 0;
1765 	}
1766 }
1767 
mcdx_requesttocdata(struct s_drive_stuff * stuffp,struct s_diskinfo * info,int tries)1768 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1769 		    int tries)
1770 {
1771 	char buf[9];
1772 	int ans;
1773 	ans =
1774 	    mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1775 	if (ans == -1) {
1776 		info->n_first = 0;
1777 		info->n_last = 0;
1778 	} else {
1779 		info->n_first = bcd2uint(buf[1]);
1780 		info->n_last = bcd2uint(buf[2]);
1781 		info->msf_leadout.minute = buf[3];
1782 		info->msf_leadout.second = buf[4];
1783 		info->msf_leadout.frame = buf[5];
1784 		info->msf_first.minute = buf[6];
1785 		info->msf_first.second = buf[7];
1786 		info->msf_first.frame = buf[8];
1787 	}
1788 	return ans;
1789 }
1790 
mcdx_setdrivemode(struct s_drive_stuff * stuffp,enum drivemodes mode,int tries)1791 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1792 		  int tries)
1793 {
1794 	char cmd[2];
1795 	int ans;
1796 
1797 	xtrace(HW, "setdrivemode() %d\n", mode);
1798 
1799 	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1800 		return -1;
1801 
1802 	switch (mode) {
1803 	case TOC:
1804 		cmd[1] |= 0x04;
1805 		break;
1806 	case DATA:
1807 		cmd[1] &= ~0x04;
1808 		break;
1809 	case RAW:
1810 		cmd[1] |= 0x40;
1811 		break;
1812 	case COOKED:
1813 		cmd[1] &= ~0x40;
1814 		break;
1815 	default:
1816 		break;
1817 	}
1818 	cmd[0] = 0x50;
1819 	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1820 }
1821 
mcdx_setdatamode(struct s_drive_stuff * stuffp,enum datamodes mode,int tries)1822 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1823 		 int tries)
1824 {
1825 	unsigned char cmd[2] = { 0xa0 };
1826 	xtrace(HW, "setdatamode() %d\n", mode);
1827 	switch (mode) {
1828 	case MODE0:
1829 		cmd[1] = 0x00;
1830 		break;
1831 	case MODE1:
1832 		cmd[1] = 0x01;
1833 		break;
1834 	case MODE2:
1835 		cmd[1] = 0x02;
1836 		break;
1837 	default:
1838 		return -EINVAL;
1839 	}
1840 	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1841 }
1842 
mcdx_config(struct s_drive_stuff * stuffp,int tries)1843 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1844 {
1845 	char cmd[4];
1846 
1847 	xtrace(HW, "config()\n");
1848 
1849 	cmd[0] = 0x90;
1850 
1851 	cmd[1] = 0x10;		/* irq enable */
1852 	cmd[2] = 0x05;		/* pre, err irq enable */
1853 
1854 	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1855 		return -1;
1856 
1857 	cmd[1] = 0x02;		/* dma select */
1858 	cmd[2] = 0x00;		/* no dma */
1859 
1860 	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1861 }
1862 
mcdx_requestversion(struct s_drive_stuff * stuffp,struct s_version * ver,int tries)1863 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1864 		    int tries)
1865 {
1866 	char buf[3];
1867 	int ans;
1868 
1869 	if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1870 				   1, buf, sizeof(buf), 2 * HZ, tries)))
1871 		return ans;
1872 
1873 	ver->code = buf[1];
1874 	ver->ver = buf[2];
1875 
1876 	return ans;
1877 }
1878 
mcdx_reset(struct s_drive_stuff * stuffp,enum resetmodes mode,int tries)1879 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1880 {
1881 	if (mode == HARD) {
1882 		outb(0, (unsigned int) stuffp->wreg_chn);	/* no dma, no irq -> hardware */
1883 		outb(0, (unsigned int) stuffp->wreg_reset);	/* hw reset */
1884 		return 0;
1885 	} else
1886 		return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1887 }
1888 
mcdx_lockdoor(struct cdrom_device_info * cdi,int lock)1889 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1890 {
1891 	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1892 	char cmd[2] = { 0xfe };
1893 
1894 	if (!(stuffp->present & DOOR))
1895 		return -ENOSYS;
1896 	if (stuffp->present & DOOR) {
1897 		cmd[1] = lock ? 0x01 : 0x00;
1898 		return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1899 	} else
1900 		return 0;
1901 }
1902 
mcdx_getstatus(struct s_drive_stuff * stuffp,int tries)1903 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1904 {
1905 	return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1906 }
1907 
1908 static int
mcdx_getval(struct s_drive_stuff * stuffp,int to,int delay,char * buf)1909 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1910 {
1911 	unsigned long timeout = to + jiffies;
1912 	char c;
1913 
1914 	if (!buf)
1915 		buf = &c;
1916 
1917 	while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1918 		if (time_after(jiffies, timeout))
1919 			return -1;
1920 		mcdx_delay(stuffp, delay);
1921 	}
1922 
1923 	*buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1924 
1925 	return 0;
1926 }
1927 
mcdx_setattentuator(struct s_drive_stuff * stuffp,struct cdrom_volctrl * vol,int tries)1928 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1929 		    struct cdrom_volctrl *vol, int tries)
1930 {
1931 	char cmd[5];
1932 	cmd[0] = 0xae;
1933 	cmd[1] = vol->channel0;
1934 	cmd[2] = 0;
1935 	cmd[3] = vol->channel1;
1936 	cmd[4] = 0;
1937 
1938 	return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1939 }
1940 
1941 MODULE_LICENSE("GPL");
1942