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