1 /* $NetBSD: gdrom.c,v 1.15 2002/11/15 13:29:26 itohy 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/device.h> 40 41 #include <sys/buf.h> 42 #include <sys/ioctl.h> 43 #include <sys/fcntl.h> 44 #include <sys/disklabel.h> 45 #include <sys/disk.h> 46 #include <sys/cdio.h> 47 #include <sys/proc.h> 48 #include <sys/conf.h> 49 50 #include <machine/sysasicvar.h> 51 52 int gdrommatch(struct device *, struct cfdata *, void *); 53 void gdromattach(struct device *, struct device *, void *); 54 55 dev_type_open(gdromopen); 56 dev_type_close(gdromclose); 57 dev_type_read(gdromread); 58 dev_type_write(gdromwrite); 59 dev_type_ioctl(gdromioctl); 60 dev_type_strategy(gdromstrategy); 61 62 const struct bdevsw gdrom_bdevsw = { 63 gdromopen, gdromclose, gdromstrategy, gdromioctl, nodump, 64 nosize, D_DISK 65 }; 66 67 const struct cdevsw gdrom_cdevsw = { 68 gdromopen, gdromclose, gdromread, gdromwrite, gdromioctl, 69 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 70 }; 71 72 struct gdrom_softc { 73 struct device sc_dv; /* generic device info; must come first */ 74 struct disk dkdev; /* generic disk info */ 75 struct buf curbuf; /* state of current I/O operation */ 76 77 int is_open, is_busy; 78 int openpart_start; /* start sector of currently open partition */ 79 80 int cmd_active; 81 void *cmd_result_buf; /* where to store result data (16 bit aligned) */ 82 int cmd_result_size; /* number of bytes allocated for buf */ 83 int cmd_actual; /* number of bytes actually read */ 84 int cmd_cond; /* resulting condition of command */ 85 }; 86 87 CFATTACH_DECL(gdrom, sizeof(struct gdrom_softc), 88 gdrommatch, gdromattach, NULL, NULL); 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 #define GDROM(o) (*(volatile unsigned char *)(0xa05f7000 + (o))) 107 108 #define GDSTATSTAT(n) ((n) & 0xf) 109 #define GDSTATDISK(n) (((n) >> 4) & 0xf) 110 111 #define GDROM_BUSY GDROM(0x18) 112 #define GDROM_DATA (*(volatile short *) & GDROM(0x80)) 113 #define GDROM_REGX GDROM(0x84) 114 #define GDROM_STAT GDROM(0x8c) 115 #define GDROM_CNTLO GDROM(0x90) 116 #define GDROM_CNTHI GDROM(0x94) 117 #define GDROM_COND GDROM(0x9c) 118 119 int gdrom_getstat(void); 120 int gdrom_do_command(struct gdrom_softc *, void *, void *, unsigned int); 121 int gdrom_command_sense(struct gdrom_softc *, void *, void *, unsigned int); 122 int gdrom_read_toc(struct gdrom_softc *, struct gd_toc *); 123 int gdrom_read_sectors(struct gdrom_softc *, void *, int, int); 124 int gdrom_mount_disk(struct gdrom_softc *); 125 int gdrom_intr(void *); 126 127 int gdrom_getstat() 128 { 129 int s1, s2, s3; 130 131 if (GDROM_BUSY & 0x80) 132 return (-1); 133 s1 = GDROM_STAT; 134 s2 = GDROM_STAT; 135 s3 = GDROM_STAT; 136 if(GDROM_BUSY & 0x80) 137 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(void *arg) 148 { 149 struct gdrom_softc *sc = arg; 150 int s, cond; 151 152 s = splbio(); 153 cond = GDROM_COND; 154 #ifdef GDROMDEBUG 155 printf("GDROM: cond = %x\n", cond); 156 #endif 157 if(!sc->cmd_active) { 158 #ifdef GDROMDEBUG 159 printf("GDROM: inactive IRQ!?\n"); 160 #endif 161 splx(s); 162 return (0); 163 } 164 165 if((cond & 8)) { 166 int cnt = (GDROM_CNTHI << 8) | GDROM_CNTLO; 167 #ifdef GDROMDEBUG 168 printf("GDROM: cnt = %d\n", cnt); 169 #endif 170 sc->cmd_actual += cnt; 171 if(cnt > 0 && sc->cmd_result_size > 0) { 172 int subcnt = (cnt > sc->cmd_result_size ? 173 sc->cmd_result_size : cnt); 174 int16_t *ptr = sc->cmd_result_buf; 175 sc->cmd_result_buf = ((char *)sc->cmd_result_buf) + 176 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) == 0) { 193 sc->cmd_cond = cond; 194 sc->cmd_active = 0; 195 wakeup(&sc->cmd_active); 196 } 197 198 splx(s); 199 return (1); 200 } 201 202 203 int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf, 204 unsigned int nbyt) 205 { 206 int i, s; 207 short *ptr = req; 208 209 while (GDROM_BUSY & 0x88) 210 ; 211 if (buf != NULL) { 212 GDROM_CNTLO = nbyt & 0xff; 213 GDROM_CNTHI = (nbyt >> 8) & 0xff; 214 GDROM_REGX = 0; 215 } 216 sc->cmd_result_buf = buf; 217 sc->cmd_result_size = nbyt; 218 219 if (GDSTATSTAT(GDROM_STAT) == 6) 220 return (-1); 221 222 GDROM_COND = 0xa0; 223 for (i = 0; i < 64; i++) 224 ; 225 while ((GDROM_BUSY & 0x88) != 8) 226 ; 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(struct gdrom_softc *sc, void *req, void *buf, 246 unsigned int nbyt) 247 { 248 /* 76543210 76543210 249 0 0x13 - 250 2 - bufsz(hi) 251 4 bufsz(lo) - 252 6 - - 253 8 - - 254 10 - - */ 255 unsigned short sense_data[5]; 256 unsigned char cmd[12]; 257 int sense_key, sense_specific; 258 259 int cond = gdrom_do_command(sc, req, buf, nbyt); 260 261 if (cond < 0) { 262 #ifdef GDROMDEBUG 263 printf("GDROM: not ready (2:58)\n"); 264 #endif 265 return (EIO); 266 } 267 268 if ((cond & 1) == 0) { 269 #ifdef GDROMDEBUG 270 printf("GDROM: no sense. 0:0\n"); 271 #endif 272 return (0); 273 } 274 275 memset(cmd, 0, sizeof(cmd)); 276 277 cmd[0] = 0x13; 278 cmd[4] = sizeof(sense_data); 279 280 gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data)); 281 282 sense_key = sense_data[1] & 0xf; 283 sense_specific = sense_data[4]; 284 if (sense_key == 11 && sense_specific == 0) { 285 #ifdef GDROMDEBUG 286 printf("GDROM: aborted (ignored). 0:0\n"); 287 #endif 288 return (0); 289 } 290 291 #ifdef GDROMDEBUG 292 printf("GDROM: SENSE %d:", sense_key); 293 printf("GDROM: %d\n", sense_specific); 294 #endif 295 296 return (sense_key == 0 ? 0 : EIO); 297 } 298 299 int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc) 300 { 301 /* 76543210 76543210 302 0 0x14 - 303 2 - bufsz(hi) 304 4 bufsz(lo) - 305 6 - - 306 8 - - 307 10 - - */ 308 unsigned char cmd[12]; 309 310 memset(cmd, 0, sizeof(cmd)); 311 312 cmd[0] = 0x14; 313 cmd[3] = sizeof(struct gd_toc) >> 8; 314 cmd[4] = sizeof(struct gd_toc) & 0xff; 315 316 return (gdrom_command_sense(sc, cmd, toc, sizeof(struct gd_toc))); 317 } 318 319 int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt) 320 { 321 /* 76543210 76543210 322 0 0x30 datafmt 323 2 sec(hi) sec(mid) 324 4 sec(lo) - 325 6 - - 326 8 cnt(hi) cnt(mid) 327 10 cnt(lo) - */ 328 unsigned char cmd[12]; 329 330 memset(cmd, 0, sizeof(cmd)); 331 332 cmd[0] = 0x30; 333 cmd[1] = 0x20; 334 cmd[2] = sector>>16; 335 cmd[3] = sector>>8; 336 cmd[4] = sector; 337 cmd[8] = cnt>>16; 338 cmd[9] = cnt>>8; 339 cmd[10] = cnt; 340 341 return (gdrom_command_sense(sc, cmd, buf, cnt << 11)); 342 } 343 344 int gdrom_mount_disk(struct gdrom_softc *sc) 345 { 346 /* 76543210 76543210 347 0 0x70 - 348 2 0x1f - 349 4 - - 350 6 - - 351 8 - - 352 10 - - */ 353 unsigned char cmd[12]; 354 355 memset(cmd, 0, sizeof(cmd)); 356 357 cmd[0] = 0x70; 358 cmd[1] = 0x1f; 359 360 return (gdrom_command_sense(sc, cmd, NULL, 0)); 361 } 362 363 int 364 gdrommatch(struct device *parent, struct cfdata *cf, void *aux) 365 { 366 static int gdrom_matched = 0; 367 368 /* Allow only once instance. */ 369 if (gdrom_matched) 370 return (0); 371 gdrom_matched = 1; 372 373 return (1); 374 } 375 376 void 377 gdromattach(struct device *parent, struct device *self, void *aux) 378 { 379 struct gdrom_softc *sc; 380 u_int32_t p, x; 381 382 sc = (struct gdrom_softc *)self; 383 384 /* 385 * Initialize and attach the disk structure. 386 */ 387 sc->dkdev.dk_name = sc->sc_dv.dv_xname; 388 sc->dkdev.dk_driver = &gdromdkdriver; 389 disk_attach(&sc->dkdev); 390 391 /* 392 * reenable disabled drive 393 */ 394 *((__volatile u_int32_t *)0xa05f74e4) = 0x1fffff; 395 for (p = 0; p < 0x200000 / 4; p++) 396 x = ((__volatile u_int32_t *)0xa0000000)[p]; 397 398 printf(": %s\n", sysasic_intr_string(IPL_BIO)); 399 sysasic_intr_establish(SYSASIC_EVENT_GDROM, IPL_BIO, gdrom_intr, sc); 400 } 401 402 int 403 gdromopen(dev_t dev, int flags, int devtype, struct proc *p) 404 { 405 struct gdrom_softc *sc; 406 int s, error, unit, cnt; 407 struct gd_toc toc; 408 409 #ifdef GDROMDEBUG 410 printf("GDROM: open\n"); 411 #endif 412 413 unit = DISKUNIT(dev); 414 if (unit >= gdrom_cd.cd_ndevs) 415 return (ENXIO); 416 417 sc = gdrom_cd.cd_devs[unit]; 418 if (sc == NULL) 419 return (ENXIO); 420 421 if (sc->is_open) 422 return (EBUSY); 423 424 s = splbio(); 425 while(sc->is_busy) 426 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 427 sc->is_busy = 1; 428 splx(s); 429 430 for (cnt = 0; cnt < 5; cnt++) 431 if ((error = gdrom_mount_disk(sc)) == 0) 432 break; 433 434 if (!error) 435 error = gdrom_read_toc(sc, &toc); 436 437 sc->is_busy = 0; 438 wakeup(&sc->is_busy); 439 440 if (error) 441 return error; 442 443 sc->is_open = 1; 444 sc->openpart_start = 150; 445 446 #ifdef GDROMDEBUG 447 printf("GDROM: open OK\n"); 448 #endif 449 return (0); 450 } 451 452 int 453 gdromclose(dev_t dev, int flags, int devtype, struct proc *p) 454 { 455 struct gdrom_softc *sc; 456 int unit; 457 #ifdef GDROMDEBUG 458 printf("GDROM: close\n"); 459 #endif 460 unit = DISKUNIT(dev); 461 sc = gdrom_cd.cd_devs[unit]; 462 463 sc->is_open = 0; 464 465 return (0); 466 } 467 468 void 469 gdromstrategy(struct buf *bp) 470 { 471 struct gdrom_softc *sc; 472 int s, unit, error; 473 #ifdef GDROMDEBUG 474 printf("GDROM: strategy\n"); 475 #endif 476 477 unit = DISKUNIT(bp->b_dev); 478 sc = gdrom_cd.cd_devs[unit]; 479 480 if (bp->b_bcount == 0) 481 goto done; 482 483 bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start; 484 485 #ifdef GDROMDEBUG 486 printf("GDROM: read_sectors(%p, %d, %ld) [%ld bytes]\n", 487 bp->b_data, bp->b_rawblkno, 488 bp->b_bcount>>11, bp->b_bcount); 489 #endif 490 s = splbio(); 491 while (sc->is_busy) 492 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 493 sc->is_busy = 1; 494 splx(s); 495 496 if ((error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno, 497 bp->b_bcount >> 11))) { 498 bp->b_error = error; 499 bp->b_flags |= B_ERROR; 500 } 501 502 sc->is_busy = 0; 503 wakeup(&sc->is_busy); 504 505 done: 506 bp->b_resid = bp->b_bcount; 507 biodone(bp); 508 } 509 510 int 511 gdromioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 512 { 513 struct gdrom_softc *sc; 514 int unit, error; 515 #ifdef GDROMDEBUG 516 printf("GDROM: ioctl %lx\n", cmd); 517 #endif 518 519 unit = DISKUNIT(dev); 520 sc = gdrom_cd.cd_devs[unit]; 521 522 switch (cmd) { 523 case CDIOREADMSADDR: { 524 int s, track, sessno = *(int *)addr; 525 struct gd_toc toc; 526 527 if (sessno != 0) 528 return (EINVAL); 529 530 s = splbio(); 531 while (sc->is_busy) 532 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 533 sc->is_busy = 1; 534 splx(s); 535 536 error = gdrom_read_toc(sc, &toc); 537 538 sc->is_busy = 0; 539 wakeup(&sc->is_busy); 540 541 if (error) 542 return error; 543 544 for (track = TOC_TRACK(toc.last); 545 track >= TOC_TRACK(toc.first); 546 --track) 547 if (TOC_CTRL(toc.entry[track-1])) 548 break; 549 550 if (track < TOC_TRACK(toc.first) || track > 100) 551 return (ENXIO); 552 553 *(int *)addr = htonl(TOC_LBA(toc.entry[track-1])) - 554 sc->openpart_start; 555 556 return (0); 557 } 558 default: 559 return (EINVAL); 560 } 561 562 #ifdef DIAGNOSTIC 563 panic("gdromioctl: impossible"); 564 #endif 565 } 566 567 568 int 569 gdromread(dev_t dev, struct uio *uio, int flags) 570 { 571 #ifdef GDROMDEBUG 572 printf("GDROM: read\n"); 573 #endif 574 return (physio(gdromstrategy, NULL, dev, B_READ, minphys, uio)); 575 } 576 577 int 578 gdromwrite(dev_t dev, struct uio *uio, int flags) 579 { 580 581 return (EROFS); 582 } 583