xref: /netbsd-src/sys/arch/dreamcast/dev/gdrom.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: gdrom.c,v 1.5 2001/07/22 15:46:42 wiz Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 Marcus Comstedt
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Marcus Comstedt.
18  * 4. Neither the name of The NetBSD Foundation nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/conf.h>
43 
44 #include <sys/buf.h>
45 #include <sys/ioctl.h>
46 #include <sys/fcntl.h>
47 #include <sys/disklabel.h>
48 #include <sys/disk.h>
49 #include <sys/cdio.h>
50 #include <sys/proc.h>
51 
52 #include <machine/conf.h>
53 #include <machine/cpu.h>
54 #include <machine/bus.h>
55 
56 #include <machine/shbvar.h>
57 #include <machine/sysasicvar.h>
58 
59 int	gdrommatch __P((struct device *, struct cfdata *, void *));
60 void	gdromattach __P((struct device *, struct device *, void *));
61 int	gdromopen __P((dev_t, int, int, struct proc *));
62 int	gdromclose __P((dev_t, int, int, struct proc *));
63 void	gdromstrategy __P((struct buf *));
64 int	gdromioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
65 int	gdromdump __P((dev_t, daddr_t, caddr_t, size_t));
66 int	gdromsize __P((dev_t));
67 int	gdromread __P((dev_t, struct uio *, int));
68 int	gdromwrite __P((dev_t, struct uio *, int));
69 
70 struct gdrom_softc {
71 	struct device sc_dv;	/* generic device info; must come first */
72 	struct disk dkdev;	/* generic disk info */
73 	struct buf_queue bufq;	/* queue pending I/O operations */
74 	struct buf curbuf;	/* state of current I/O operation */
75 
76 	int is_open, is_busy;
77 	int openpart_start;	/* start sector of currently open partition */
78 
79 	int cmd_active;
80 	void *cmd_result_buf;	/* where to store result data (16 bit aligned) */
81 	int cmd_result_size;	/* number of bytes allocated for buf */
82 	int cmd_actual;		/* number of bytes actually read */
83 	int cmd_cond;		/* resulting condition of command */
84 };
85 
86 struct cfattach gdrom_ca = {
87 	sizeof(struct gdrom_softc), gdrommatch, gdromattach
88 };
89 
90 struct dkdriver gdromdkdriver = { gdromstrategy };
91 
92 extern struct cfdriver gdrom_cd;
93 
94 
95 struct gd_toc {
96   unsigned int entry[99];
97   unsigned int first, last;
98   unsigned int leadout;
99 };
100 
101 #define TOC_LBA(n) ((n)&0xffffff00)
102 #define TOC_ADR(n) ((n)&0x0f)
103 #define TOC_CTRL(n) (((n)&0xf0)>>4)
104 #define TOC_TRACK(n) (((n)&0x0000ff00)>>8)
105 
106 
107 #define GDROM(o) (*(volatile unsigned char *)(0xa05f7000+(o)))
108 
109 #define GDSTATSTAT(n) ((n)&0xf)
110 #define GDSTATDISK(n) (((n)>>4)&0xf)
111 
112 #define GDROM_BUSY  GDROM(0x18)
113 #define GDROM_DATA  (*(volatile short *)&GDROM(0x80))
114 #define GDROM_REGX  GDROM(0x84)
115 #define GDROM_STAT  GDROM(0x8c)
116 #define GDROM_CNTLO GDROM(0x90)
117 #define GDROM_CNTHI GDROM(0x94)
118 #define GDROM_COND  GDROM(0x9c)
119 
120 int	gdrom_getstat	__P((void));
121 int	gdrom_do_command	__P((struct gdrom_softc *sc, void *req, void *buf, unsigned int nbyt));
122 int	gdrom_command_sense	__P((struct gdrom_softc *sc, void *req, void *buf, unsigned int nbyt));
123 int	gdrom_read_toc	__P((struct gdrom_softc *sc, struct gd_toc *toc));
124 int	gdrom_read_sectors	__P((struct gdrom_softc *sc, void *buf, int sector, int cnt));
125 int	gdrom_mount_disk	__P((struct gdrom_softc *sc));
126 int	gdrom_intr 	__P((void* arg));
127 
128 
129 int gdrom_getstat()
130 {
131 	int s1, s2, s3;
132 
133 	if(GDROM_BUSY & 0x80) return -1;
134 	s1 = GDROM_STAT;
135 	s2 = GDROM_STAT;
136 	s3 = GDROM_STAT;
137 	if(GDROM_BUSY & 0x80) return -1;
138 	if(s1 == s2)
139 	  return s1;
140 	else if(s2 == s3)
141 	  return s2;
142 	else
143 	  return -1;
144 }
145 
146 int
147 gdrom_intr(arg)
148 	void *arg;
149 {
150 	struct gdrom_softc *sc = arg;
151 	int s, cond;
152 
153 	s = splbio();
154 	cond = GDROM_COND;
155 #ifdef GDROMDEBUG
156 	printf("GDROM: cond = %x\n", cond);
157 #endif
158 	if(!sc->cmd_active) {
159 #ifdef GDROMDEBUG
160 	  printf("GDROM: inactive IRQ!?\n");
161 #endif
162 	  splx(s);
163 	  return 0;
164 	}
165 
166 	if((cond & 8)) {
167 		int cnt = (GDROM_CNTHI<<8) | GDROM_CNTLO;
168 #ifdef GDROMDEBUG
169 		printf("GDROM: cnt = %d\n", cnt);
170 #endif
171 		sc->cmd_actual += cnt;
172 		if(cnt > 0 && sc->cmd_result_size > 0) {
173 			int subcnt = (cnt > sc->cmd_result_size?
174 				      sc->cmd_result_size : cnt);
175 			int16_t *ptr = sc->cmd_result_buf;
176 			sc->cmd_result_buf = ((char *)sc->cmd_result_buf)+subcnt;
177 			sc->cmd_result_size -= subcnt;
178 			cnt -= subcnt;
179 			while(subcnt > 0) {
180 			  *ptr++ = GDROM_DATA;
181 			  subcnt -= 2;
182 			}
183 		}
184 		while(cnt > 0) {
185 		  __volatile int16_t tmp;
186 		  tmp = GDROM_DATA;
187 		  cnt -= 2;
188 		}
189 	}
190 	while( GDROM_BUSY & 0x80 );
191 
192 	if(!(cond & 8)) {
193 		sc->cmd_cond = cond;
194 		sc->cmd_active = 0;
195 		wakeup(&sc->cmd_active);
196 	}
197 
198 	splx(s);
199 	return 0;
200 }
201 
202 
203 int gdrom_do_command(sc, req, buf, nbyt)
204 	struct gdrom_softc *sc;
205 	void *req;
206 	void *buf;
207 	unsigned int nbyt;
208 {
209 	int i, s;
210 	short *ptr = req;
211 
212 	while( GDROM_BUSY & 0x88 ) ;
213 	if(buf != NULL) {
214 	  GDROM_CNTLO = nbyt & 0xff;
215 	  GDROM_CNTHI = (nbyt >> 8) & 0xff;
216 	  GDROM_REGX = 0;
217 	}
218 	sc->cmd_result_buf = buf;
219 	sc->cmd_result_size = nbyt;
220 
221 	if(GDSTATSTAT(GDROM_STAT) == 6)
222 	  return (-1);
223 
224 	GDROM_COND = 0xa0;
225 	for(i = 0; i < 64; i++) ;
226 	while( (GDROM_BUSY & 0x88) != 8 ) ;
227 
228 	s = splbio();
229 
230 	sc->cmd_actual = 0;
231 	sc->cmd_active = 1;
232 
233 	for(i = 0; i< 6; i++)
234 	  GDROM_DATA = ptr[i];
235 
236 	while(sc->cmd_active)
237 	  tsleep(&sc->cmd_active, PRIBIO, "gdrom", 0);
238 
239 	splx(s);
240 
241 	return sc->cmd_cond;
242 }
243 
244 
245 int gdrom_command_sense(sc, req, buf, nbyt)
246 	struct gdrom_softc *sc;
247 	void *req;
248 	void *buf;
249 	unsigned int nbyt;
250 {
251 	/* 76543210 76543210
252 	 0   0x13      -
253 	 2    -      bufsz(hi)
254 	 4 bufsz(lo)   -
255 	 6    -        -
256 	 8    -        -
257 	 10    -        -        */
258 	unsigned short sense_data[5];
259 	unsigned char cmd[12];
260 	int sense_key, sense_specific;
261 
262 	int cond = gdrom_do_command(sc, req, buf, nbyt);
263 
264 	if(cond < 0) {
265 #ifdef GDROMDEBUG
266 	  printf("GDROM: not ready (2:58)\n");
267 #endif
268 	  return EIO;
269 	}
270 
271 	if(!(cond & 1)) {
272 #ifdef GDROMDEBUG
273 	  printf("GDROM: no sense.  0:0\n");
274 #endif
275 	  return (0);
276 	}
277 
278 	memset(cmd, 0, sizeof(cmd));
279 
280 	cmd[0] = 0x13;
281 	cmd[4] = sizeof(sense_data);
282 
283 	gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data));
284 
285 	sense_key = sense_data[1] & 0xf;
286 	sense_specific = sense_data[4];
287 	if(sense_key == 11 && sense_specific == 0) {
288 #ifdef GDROMDEBUG
289 	  printf("GDROM: aborted (ignored).  0:0\n");
290 #endif
291 	  return (0);
292 	}
293 
294 #ifdef GDROMDEBUG
295 	printf("GDROM: SENSE %d:", sense_key);
296 	printf("GDROM: %d\n", sense_specific);
297 #endif
298 
299 	return (sense_key==0? 0 : EIO);
300 }
301 
302 int gdrom_read_toc(sc, toc)
303 	struct gdrom_softc *sc;
304 	struct gd_toc *toc;
305 {
306 	/* 76543210 76543210
307 	 0   0x14      -
308 	 2    -      bufsz(hi)
309 	 4 bufsz(lo)   -
310 	 6    -        -
311 	 8    -        -
312 	 10    -        -        */
313 	unsigned char cmd[12];
314 
315 	memset(cmd, 0, sizeof(cmd));
316 
317 	cmd[0] = 0x14;
318 	cmd[3] = sizeof(struct gd_toc)>>8;
319 	cmd[4] = sizeof(struct gd_toc)&0xff;
320 
321 	return gdrom_command_sense( sc, cmd, toc, sizeof(struct gd_toc) );
322 }
323 
324 int gdrom_read_sectors(sc, buf, sector, cnt)
325 	struct gdrom_softc *sc;
326 	void *buf;
327 	int sector;
328 	int cnt;
329 {
330 	/* 76543210 76543210
331 	 0   0x30    datafmt
332 	 2  sec(hi)  sec(mid)
333 	 4  sec(lo)    -
334 	 6    -        -
335 	 8  cnt(hi)  cnt(mid)
336 	 10  cnt(lo)    -        */
337 	unsigned char cmd[12];
338 
339 	memset(cmd, 0, sizeof(cmd));
340 
341 	cmd[0] = 0x30;
342 	cmd[1] = 0x20;
343 	cmd[2] = sector>>16;
344 	cmd[3] = sector>>8;
345 	cmd[4] = sector;
346 	cmd[8] = cnt>>16;
347 	cmd[9] = cnt>>8;
348 	cmd[10] = cnt;
349 
350 	return gdrom_command_sense( sc, cmd, buf, cnt<<11 );
351 }
352 
353 int gdrom_mount_disk(sc)
354 	struct gdrom_softc *sc;
355 {
356 	/* 76543210 76543210
357 	 0   0x70      -
358 	 2   0x1f      -
359 	 4    -        -
360 	 6    -        -
361 	 8    -        -
362 	 10    -        -        */
363 	unsigned char cmd[12];
364 
365 	memset(cmd, 0, sizeof(cmd));
366 
367 	cmd[0] = 0x70;
368 	cmd[1] = 0x1f;
369 
370 	return gdrom_command_sense( sc, cmd, NULL, 0 );
371 }
372 
373 
374 
375 
376 int
377 gdrommatch(pdp, cfp, auxp)
378 	struct device *pdp;
379 	struct cfdata *cfp;
380 	void *auxp;
381 {
382 	static int gdrom_matched = 0;
383   	struct shb_attach_args *sa = auxp;
384 
385 	/* Allow only once instance. */
386 	if (strcmp("gdrom", cfp->cf_driver->cd_name) || gdrom_matched)
387 		return(0);
388 	gdrom_matched = 1;
389 	sa->ia_iosize = 0 /* 0x100 */;
390 	return(1);
391 }
392 
393 void
394 gdromattach(pdp, dp, auxp)
395 	struct device *pdp, *dp;
396 	void *auxp;
397 {
398 	struct gdrom_softc *sc;
399 
400 	sc = (struct gdrom_softc *)dp;
401 
402 	BUFQ_INIT(&sc->bufq);
403 
404 	printf("\n");
405 
406 	/*
407 	 * Initialize and attach the disk structure.
408 	 */
409 	sc->dkdev.dk_name = sc->sc_dv.dv_xname;
410 	sc->dkdev.dk_driver = &gdromdkdriver;
411 	disk_attach(&sc->dkdev);
412 
413 	/*
414 	 * reenable disabled drive
415 	 */
416 	{
417 	  register u_int32_t p, x;
418 
419 	  *((volatile u_int32_t *)0xa05f74e4) = 0x1fffff;
420 	  for(p=0; p<0x200000/4; p++)
421 	    x = ((volatile u_int32_t *)0xa0000000)[p];
422 	}
423 
424 	sysasic_intr_establish(9, SYSASIC_EVENT_GDROM, 0, gdrom_intr, sc);
425 }
426 
427 int
428 gdromopen(dev, flags, devtype, p)
429 	dev_t dev;
430 	int flags, devtype;
431 	struct proc *p;
432 {
433 	struct gdrom_softc *sc;
434 	int s, error, unit, cnt;
435 	struct gd_toc toc;
436 
437 #ifdef GDROMDEBUG
438 	printf("GDROM: open\n");
439 #endif
440 
441 	unit = DISKUNIT(dev);
442 	if (unit >= gdrom_cd.cd_ndevs)
443 		return (ENXIO);
444 
445 	sc = gdrom_cd.cd_devs[unit];
446 	if (sc == NULL)
447 		return (ENXIO);
448 
449 	if (sc->is_open)
450 		return (EBUSY);
451 
452 	s = splbio();
453 	while(sc->is_busy)
454 	  tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
455 	sc->is_busy = 1;
456 	splx(s);
457 
458 	for (cnt = 0; cnt < 5; cnt++)
459 	  if ((error = gdrom_mount_disk(sc)) == 0)
460 	    break;
461 
462 	if (!error)
463 		error = gdrom_read_toc(sc, &toc);
464 
465 	sc->is_busy = 0;
466 	wakeup(&sc->is_busy);
467 
468 	if (error)
469 		return error;
470 
471 	sc->is_open = 1;
472 	sc->openpart_start = 150;
473 
474 #ifdef GDROMDEBUG
475 	printf("GDROM: open OK\n");
476 #endif
477 	return (0);
478 }
479 
480 int
481 gdromclose(dev, flags, devtype, p)
482 	dev_t dev;
483 	int flags, devtype;
484 	struct proc *p;
485 {
486 	struct gdrom_softc *sc;
487 	int unit;
488 #ifdef GDROMDEBUG
489 	printf("GDROM: close\n");
490 #endif
491 	unit = DISKUNIT(dev);
492 	sc = gdrom_cd.cd_devs[unit];
493 
494 	sc->is_open = 0;
495 
496 	return (0);
497 }
498 
499 void
500 gdromstrategy(bp)
501 	struct buf *bp;
502 {
503 	struct gdrom_softc *sc;
504 	int s, unit, error;
505 #ifdef GDROMDEBUG
506 	printf("GDROM: strategy\n");
507 #endif
508 
509 	unit = DISKUNIT(bp->b_dev);
510 	sc = gdrom_cd.cd_devs[unit];
511 
512 	if (bp->b_bcount == 0)
513 	  goto done;
514 
515 	bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start;
516 
517 #ifdef GDROMDEBUG
518 	printf("GDROM: read_sectors(%p, %d, %ld) [%ld bytes]\n",
519 	       bp->b_data, bp->b_rawblkno,
520 	       bp->b_bcount>>11, bp->b_bcount);
521 #endif
522 	s = splbio();
523 	while(sc->is_busy)
524 	  tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
525 	sc->is_busy = 1;
526 	splx(s);
527 
528 	if (error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno,
529 				       bp->b_bcount>>11)) {
530 	  bp->b_error = error;
531 	  bp->b_flags |= B_ERROR;
532 	}
533 
534 	sc->is_busy = 0;
535 	wakeup(&sc->is_busy);
536 
537 done:
538 	bp->b_resid = bp->b_bcount;
539 	biodone(bp);
540 }
541 
542 int
543 gdromioctl(dev, cmd, addr, flag, p)
544 	dev_t dev;
545 	u_long cmd;
546 	caddr_t addr;
547 	int flag;
548 	struct proc *p;
549 {
550 	struct gdrom_softc *sc;
551 	int unit, error;
552 #ifdef GDROMDEBUG
553 	printf("GDROM: ioctl %lx\n", cmd);
554 #endif
555 
556 	unit = DISKUNIT(dev);
557 	sc = gdrom_cd.cd_devs[unit];
558 
559 	switch (cmd) {
560 	case CDIOREADMSADDR: {
561 		int s, track, sessno = *(int*)addr;
562 		struct gd_toc toc;
563 
564 		if (sessno != 0)
565 			return (EINVAL);
566 
567 		s = splbio();
568 		while(sc->is_busy)
569 		  tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
570 		sc->is_busy = 1;
571 		splx(s);
572 
573 		error = gdrom_read_toc(sc, &toc);
574 
575 		sc->is_busy = 0;
576 		wakeup(&sc->is_busy);
577 
578 		if (error)
579 		  return error;
580 
581 		for (track = TOC_TRACK(toc.last);
582 		     track >= TOC_TRACK(toc.first);
583 		     --track)
584 		  if (TOC_CTRL(toc.entry[track-1]))
585 		    break;
586 
587 		if (track < TOC_TRACK(toc.first) || track > 100)
588 		  return (ENXIO);
589 
590 		*(int*)addr = htonl(TOC_LBA(toc.entry[track-1])) -
591 		  sc->openpart_start;
592 
593 		return 0;
594 	}
595 	 default:
596 	   return (EINVAL);
597 	}
598 
599 #ifdef DIAGNOSTIC
600 	panic("gdromioctl: impossible");
601 #endif
602 }
603 
604 
605 /*
606  * Can't dump to CD; read only media...
607  */
608 int
609 gdromdump(dev, blkno, va, size)
610 	dev_t	dev;
611 	daddr_t	blkno;
612 	caddr_t	va;
613 	size_t	size;
614 {
615 	return (EINVAL);
616 }
617 
618 int
619 gdromsize(dev)
620 	dev_t dev;
621 {
622 	return (-1);
623 }
624 
625 int
626 gdromread(dev, uio, flags)
627 	dev_t	dev;
628 	struct	uio *uio;
629 	int	flags;
630 {
631 #ifdef GDROMDEBUG
632 	printf("GDROM: read\n");
633 #endif
634 	return (physio(gdromstrategy, NULL, dev, B_READ, minphys, uio));
635 }
636 
637 int
638 gdromwrite(dev, uio, flags)
639 	dev_t	dev;
640 	struct	uio *uio;
641 	int	flags;
642 {
643 	return (EROFS);
644 }
645 
646