Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.14 1031 lines 20 kB view raw
1#define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>" 2 3/* 4 linux/drivers/block/gscd.c - GoldStar R420 CDROM driver 5 6 Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> 7 based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de> 8 9 10 For all kind of other information about the GoldStar CDROM 11 and this Linux device driver I installed a WWW-URL: 12 http://linux.rz.fh-hannover.de/~raupach 13 14 15 If you are the editor of a Linux CD, you should 16 enable gscd.c within your boot floppy kernel and 17 send me one of your CDs for free. 18 19 20 -------------------------------------------------------------------- 21 This program is free software; you can redistribute it and/or modify 22 it under the terms of the GNU General Public License as published by 23 the Free Software Foundation; either version 2, or (at your option) 24 any later version. 25 26 This program is distributed in the hope that it will be useful, 27 but WITHOUT ANY WARRANTY; without even the implied warranty of 28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 GNU General Public License for more details. 30 31 You should have received a copy of the GNU General Public License 32 along with this program; if not, write to the Free Software 33 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 34 35 -------------------------------------------------------------------- 36 37 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 38 Removed init_module & cleanup_module in favor of 39 module_init & module_exit. 40 Torben Mathiasen <tmm@image.dk> 41 42*/ 43 44/* These settings are for various debug-level. Leave they untouched ... */ 45#define NO_GSCD_DEBUG 46#define NO_IOCTL_DEBUG 47#define NO_MODULE_DEBUG 48#define NO_FUTURE_WORK 49/*------------------------*/ 50 51#include <linux/module.h> 52 53#include <linux/slab.h> 54#include <linux/errno.h> 55#include <linux/signal.h> 56#include <linux/sched.h> 57#include <linux/timer.h> 58#include <linux/fs.h> 59#include <linux/mm.h> 60#include <linux/kernel.h> 61#include <linux/cdrom.h> 62#include <linux/ioport.h> 63#include <linux/major.h> 64#include <linux/string.h> 65#include <linux/init.h> 66 67#include <asm/system.h> 68#include <asm/io.h> 69#include <asm/uaccess.h> 70 71#define MAJOR_NR GOLDSTAR_CDROM_MAJOR 72#include <linux/blkdev.h> 73#include "gscd.h" 74 75static int gscdPresent = 0; 76 77static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ 78static int gscd_bn = -1; 79static short gscd_port = GSCD_BASE_ADDR; 80module_param_named(gscd, gscd_port, short, 0); 81 82/* Kommt spaeter vielleicht noch mal dran ... 83 * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); 84 */ 85 86static void gscd_read_cmd(struct request *req); 87static void gscd_hsg2msf(long hsg, struct msf *msf); 88static void gscd_bin2bcd(unsigned char *p); 89 90/* Schnittstellen zum Kern/FS */ 91 92static void __do_gscd_request(unsigned long dummy); 93static int gscd_ioctl(struct inode *, struct file *, unsigned int, 94 unsigned long); 95static int gscd_open(struct inode *, struct file *); 96static int gscd_release(struct inode *, struct file *); 97static int check_gscd_med_chg(struct gendisk *disk); 98 99/* GoldStar Funktionen */ 100 101static void cmd_out(int, char *, char *, int); 102static void cmd_status(void); 103static void init_cd_drive(int); 104 105static int get_status(void); 106static void clear_Audio(void); 107static void cc_invalidate(void); 108 109/* some things for the next version */ 110#ifdef FUTURE_WORK 111static void update_state(void); 112static long gscd_msf2hsg(struct msf *mp); 113static int gscd_bcd2bin(unsigned char bcd); 114#endif 115 116 117/* lo-level cmd-Funktionen */ 118 119static void cmd_info_in(char *, int); 120static void cmd_end(void); 121static void cmd_read_b(char *, int, int); 122static void cmd_read_w(char *, int, int); 123static int cmd_unit_alive(void); 124static void cmd_write_cmd(char *); 125 126 127/* GoldStar Variablen */ 128 129static int curr_drv_state; 130static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 131static int drv_mode; 132static int disk_state; 133static int speed; 134static int ndrives; 135 136static unsigned char drv_num_read; 137static unsigned char f_dsk_valid; 138static unsigned char current_drive; 139static unsigned char f_drv_ok; 140 141 142static char f_AudioPlay; 143static char f_AudioPause; 144static int AudioStart_m; 145static int AudioStart_f; 146static int AudioEnd_m; 147static int AudioEnd_f; 148 149static DEFINE_TIMER(gscd_timer, NULL, 0, 0); 150static DEFINE_SPINLOCK(gscd_lock); 151static struct request_queue *gscd_queue; 152 153static struct block_device_operations gscd_fops = { 154 .owner = THIS_MODULE, 155 .open = gscd_open, 156 .release = gscd_release, 157 .ioctl = gscd_ioctl, 158 .media_changed = check_gscd_med_chg, 159}; 160 161/* 162 * Checking if the media has been changed 163 * (not yet implemented) 164 */ 165static int check_gscd_med_chg(struct gendisk *disk) 166{ 167#ifdef GSCD_DEBUG 168 printk("gscd: check_med_change\n"); 169#endif 170 return 0; 171} 172 173 174#ifndef MODULE 175/* Using new interface for kernel-parameters */ 176 177static int __init gscd_setup(char *str) 178{ 179 int ints[2]; 180 (void) get_options(str, ARRAY_SIZE(ints), ints); 181 182 if (ints[0] > 0) { 183 gscd_port = ints[1]; 184 } 185 return 1; 186} 187 188__setup("gscd=", gscd_setup); 189 190#endif 191 192static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, 193 unsigned long arg) 194{ 195 unsigned char to_do[10]; 196 unsigned char dummy; 197 198 199 switch (cmd) { 200 case CDROMSTART: /* Spin up the drive */ 201 /* Don't think we can do this. Even if we could, 202 * I think the drive times out and stops after a while 203 * anyway. For now, ignore it. 204 */ 205 return 0; 206 207 case CDROMRESUME: /* keine Ahnung was das ist */ 208 return 0; 209 210 211 case CDROMEJECT: 212 cmd_status(); 213 to_do[0] = CMD_TRAY_CTL; 214 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); 215 216 return 0; 217 218 default: 219 return -EINVAL; 220 } 221 222} 223 224 225/* 226 * Take care of the different block sizes between cdrom and Linux. 227 * When Linux gets variable block sizes this will probably go away. 228 */ 229 230static void gscd_transfer(struct request *req) 231{ 232 while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { 233 long offs = (req->sector & 3) * 512; 234 memcpy(req->buffer, gscd_buf + offs, 512); 235 req->nr_sectors--; 236 req->sector++; 237 req->buffer += 512; 238 } 239} 240 241 242/* 243 * I/O request routine called from Linux kernel. 244 */ 245 246static void do_gscd_request(request_queue_t * q) 247{ 248 __do_gscd_request(0); 249} 250 251static void __do_gscd_request(unsigned long dummy) 252{ 253 struct request *req; 254 unsigned int block; 255 unsigned int nsect; 256 257repeat: 258 req = elv_next_request(gscd_queue); 259 if (!req) 260 return; 261 262 block = req->sector; 263 nsect = req->nr_sectors; 264 265 if (req->sector == -1) 266 goto out; 267 268 if (req->cmd != READ) { 269 printk("GSCD: bad cmd %lu\n", rq_data_dir(req)); 270 end_request(req, 0); 271 goto repeat; 272 } 273 274 gscd_transfer(req); 275 276 /* if we satisfied the request from the buffer, we're done. */ 277 278 if (req->nr_sectors == 0) { 279 end_request(req, 1); 280 goto repeat; 281 } 282#ifdef GSCD_DEBUG 283 printk("GSCD: block %d, nsect %d\n", block, nsect); 284#endif 285 gscd_read_cmd(req); 286out: 287 return; 288} 289 290 291 292/* 293 * Check the result of the set-mode command. On success, send the 294 * read-data command. 295 */ 296 297static void gscd_read_cmd(struct request *req) 298{ 299 long block; 300 struct gscd_Play_msf gscdcmd; 301 char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ 302 303 cmd_status(); 304 if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { 305 printk("GSCD: no disk or door open\n"); 306 end_request(req, 0); 307 } else { 308 if (disk_state & ST_INVALID) { 309 printk("GSCD: disk invalid\n"); 310 end_request(req, 0); 311 } else { 312 gscd_bn = -1; /* purge our buffer */ 313 block = req->sector / 4; 314 gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ 315 316 cmd[2] = gscdcmd.start.min; 317 cmd[3] = gscdcmd.start.sec; 318 cmd[4] = gscdcmd.start.frame; 319 320#ifdef GSCD_DEBUG 321 printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], 322 cmd[4]); 323#endif 324 cmd_out(TYPE_DATA, (char *) &cmd, 325 (char *) &gscd_buf[0], 1); 326 327 gscd_bn = req->sector / 4; 328 gscd_transfer(req); 329 end_request(req, 1); 330 } 331 } 332 SET_TIMER(__do_gscd_request, 1); 333} 334 335 336/* 337 * Open the device special file. Check that a disk is in. 338 */ 339 340static int gscd_open(struct inode *ip, struct file *fp) 341{ 342 int st; 343 344#ifdef GSCD_DEBUG 345 printk("GSCD: open\n"); 346#endif 347 348 if (gscdPresent == 0) 349 return -ENXIO; /* no hardware */ 350 351 get_status(); 352 st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); 353 if (st) { 354 printk("GSCD: no disk or door open\n"); 355 return -ENXIO; 356 } 357 358/* if (updateToc() < 0) 359 return -EIO; 360*/ 361 362 return 0; 363} 364 365 366/* 367 * On close, we flush all gscd blocks from the buffer cache. 368 */ 369 370static int gscd_release(struct inode *inode, struct file *file) 371{ 372 373#ifdef GSCD_DEBUG 374 printk("GSCD: release\n"); 375#endif 376 377 gscd_bn = -1; 378 379 return 0; 380} 381 382 383static int get_status(void) 384{ 385 int status; 386 387 cmd_status(); 388 status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); 389 390 if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) { 391 cc_invalidate(); 392 return 1; 393 } else { 394 return 0; 395 } 396} 397 398 399static void cc_invalidate(void) 400{ 401 drv_num_read = 0xFF; 402 f_dsk_valid = 0xFF; 403 current_drive = 0xFF; 404 f_drv_ok = 0xFF; 405 406 clear_Audio(); 407 408} 409 410static void clear_Audio(void) 411{ 412 413 f_AudioPlay = 0; 414 f_AudioPause = 0; 415 AudioStart_m = 0; 416 AudioStart_f = 0; 417 AudioEnd_m = 0; 418 AudioEnd_f = 0; 419 420} 421 422/* 423 * waiting ? 424 */ 425 426static int wait_drv_ready(void) 427{ 428 int found, read; 429 430 do { 431 found = inb(GSCDPORT(0)); 432 found &= 0x0f; 433 read = inb(GSCDPORT(0)); 434 read &= 0x0f; 435 } while (read != found); 436 437#ifdef GSCD_DEBUG 438 printk("Wait for: %d\n", read); 439#endif 440 441 return read; 442} 443 444static void cc_Ident(char *respons) 445{ 446 char to_do[] = { CMD_IDENT, 0, 0 }; 447 448 cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E); 449 450} 451 452static void cc_SetSpeed(void) 453{ 454 char to_do[] = { CMD_SETSPEED, 0, 0 }; 455 char dummy; 456 457 if (speed > 0) { 458 to_do[1] = speed & 0x0F; 459 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); 460 } 461} 462 463static void cc_Reset(void) 464{ 465 char to_do[] = { CMD_RESET, 0 }; 466 char dummy; 467 468 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); 469} 470 471static void cmd_status(void) 472{ 473 char to_do[] = { CMD_STATUS, 0 }; 474 char dummy; 475 476 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); 477 478#ifdef GSCD_DEBUG 479 printk("GSCD: Status: %d\n", disk_state); 480#endif 481 482} 483 484static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count) 485{ 486 int result; 487 488 489 result = wait_drv_ready(); 490 if (result != drv_mode) { 491 unsigned long test_loops = 0xFFFF; 492 int i, dummy; 493 494 outb(curr_drv_state, GSCDPORT(0)); 495 496 /* LOCLOOP_170 */ 497 do { 498 result = wait_drv_ready(); 499 test_loops--; 500 } while ((result != drv_mode) && (test_loops > 0)); 501 502 if (result != drv_mode) { 503 disk_state = ST_x08 | ST_x04 | ST_INVALID; 504 return; 505 } 506 507 /* ...and waiting */ 508 for (i = 1, dummy = 1; i < 0xFFFF; i++) { 509 dummy *= i; 510 } 511 } 512 513 /* LOC_172 */ 514 /* check the unit */ 515 /* and wake it up */ 516 if (cmd_unit_alive() != 0x08) { 517 /* LOC_174 */ 518 /* game over for this unit */ 519 disk_state = ST_x08 | ST_x04 | ST_INVALID; 520 return; 521 } 522 523 /* LOC_176 */ 524#ifdef GSCD_DEBUG 525 printk("LOC_176 "); 526#endif 527 if (drv_mode == 0x09) { 528 /* magic... */ 529 printk("GSCD: magic ...\n"); 530 outb(result, GSCDPORT(2)); 531 } 532 533 /* write the command to the drive */ 534 cmd_write_cmd(cmd); 535 536 /* LOC_178 */ 537 for (;;) { 538 result = wait_drv_ready(); 539 if (result != drv_mode) { 540 /* LOC_179 */ 541 if (result == 0x04) { /* Mode 4 */ 542 /* LOC_205 */ 543#ifdef GSCD_DEBUG 544 printk("LOC_205 "); 545#endif 546 disk_state = inb(GSCDPORT(2)); 547 548 do { 549 result = wait_drv_ready(); 550 } while (result != drv_mode); 551 return; 552 553 } else { 554 if (result == 0x06) { /* Mode 6 */ 555 /* LOC_181 */ 556#ifdef GSCD_DEBUG 557 printk("LOC_181 "); 558#endif 559 560 if (cmd_type == TYPE_DATA) { 561 /* read data */ 562 /* LOC_184 */ 563 if (drv_mode == 9) { 564 /* read the data to the buffer (word) */ 565 566 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ 567 cmd_read_w 568 (respo_buf, 569 respo_count, 570 CD_FRAMESIZE / 571 2); 572 return; 573 } else { 574 /* read the data to the buffer (byte) */ 575 576 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ 577 cmd_read_b 578 (respo_buf, 579 respo_count, 580 CD_FRAMESIZE); 581 return; 582 } 583 } else { 584 /* read the info to the buffer */ 585 cmd_info_in(respo_buf, 586 respo_count); 587 return; 588 } 589 590 return; 591 } 592 } 593 594 } else { 595 disk_state = ST_x08 | ST_x04 | ST_INVALID; 596 return; 597 } 598 } /* for (;;) */ 599 600 601#ifdef GSCD_DEBUG 602 printk("\n"); 603#endif 604} 605 606 607static void cmd_write_cmd(char *pstr) 608{ 609 int i, j; 610 611 /* LOC_177 */ 612#ifdef GSCD_DEBUG 613 printk("LOC_177 "); 614#endif 615 616 /* calculate the number of parameter */ 617 j = *pstr & 0x0F; 618 619 /* shift it out */ 620 for (i = 0; i < j; i++) { 621 outb(*pstr, GSCDPORT(2)); 622 pstr++; 623 } 624} 625 626 627static int cmd_unit_alive(void) 628{ 629 int result; 630 unsigned long max_test_loops; 631 632 633 /* LOC_172 */ 634#ifdef GSCD_DEBUG 635 printk("LOC_172 "); 636#endif 637 638 outb(curr_drv_state, GSCDPORT(0)); 639 max_test_loops = 0xFFFF; 640 641 do { 642 result = wait_drv_ready(); 643 max_test_loops--; 644 } while ((result != 0x08) && (max_test_loops > 0)); 645 646 return result; 647} 648 649 650static void cmd_info_in(char *pb, int count) 651{ 652 int result; 653 char read; 654 655 656 /* read info */ 657 /* LOC_182 */ 658#ifdef GSCD_DEBUG 659 printk("LOC_182 "); 660#endif 661 662 do { 663 read = inb(GSCDPORT(2)); 664 if (count > 0) { 665 *pb = read; 666 pb++; 667 count--; 668 } 669 670 /* LOC_183 */ 671 do { 672 result = wait_drv_ready(); 673 } while (result == 0x0E); 674 } while (result == 6); 675 676 cmd_end(); 677 return; 678} 679 680 681static void cmd_read_b(char *pb, int count, int size) 682{ 683 int result; 684 int i; 685 686 687 /* LOC_188 */ 688 /* LOC_189 */ 689#ifdef GSCD_DEBUG 690 printk("LOC_189 "); 691#endif 692 693 do { 694 do { 695 result = wait_drv_ready(); 696 } while (result != 6 || result == 0x0E); 697 698 if (result != 6) { 699 cmd_end(); 700 return; 701 } 702#ifdef GSCD_DEBUG 703 printk("LOC_191 "); 704#endif 705 706 for (i = 0; i < size; i++) { 707 *pb = inb(GSCDPORT(2)); 708 pb++; 709 } 710 count--; 711 } while (count > 0); 712 713 cmd_end(); 714 return; 715} 716 717 718static void cmd_end(void) 719{ 720 int result; 721 722 723 /* LOC_204 */ 724#ifdef GSCD_DEBUG 725 printk("LOC_204 "); 726#endif 727 728 do { 729 result = wait_drv_ready(); 730 if (result == drv_mode) { 731 return; 732 } 733 } while (result != 4); 734 735 /* LOC_205 */ 736#ifdef GSCD_DEBUG 737 printk("LOC_205 "); 738#endif 739 740 disk_state = inb(GSCDPORT(2)); 741 742 do { 743 result = wait_drv_ready(); 744 } while (result != drv_mode); 745 return; 746 747} 748 749 750static void cmd_read_w(char *pb, int count, int size) 751{ 752 int result; 753 int i; 754 755 756#ifdef GSCD_DEBUG 757 printk("LOC_185 "); 758#endif 759 760 do { 761 /* LOC_185 */ 762 do { 763 result = wait_drv_ready(); 764 } while (result != 6 || result == 0x0E); 765 766 if (result != 6) { 767 cmd_end(); 768 return; 769 } 770 771 for (i = 0; i < size; i++) { 772 /* na, hier muss ich noch mal drueber nachdenken */ 773 *pb = inw(GSCDPORT(2)); 774 pb++; 775 } 776 count--; 777 } while (count > 0); 778 779 cmd_end(); 780 return; 781} 782 783static int __init find_drives(void) 784{ 785 int *pdrv; 786 int drvnum; 787 int subdrv; 788 int i; 789 790 speed = 0; 791 pdrv = (int *) &drv_states; 792 curr_drv_state = 0xFE; 793 subdrv = 0; 794 drvnum = 0; 795 796 for (i = 0; i < 8; i++) { 797 subdrv++; 798 cmd_status(); 799 disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; 800 if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) { 801 /* LOC_240 */ 802 *pdrv = curr_drv_state; 803 init_cd_drive(drvnum); 804 pdrv++; 805 drvnum++; 806 } else { 807 if (subdrv < 2) { 808 continue; 809 } else { 810 subdrv = 0; 811 } 812 } 813 814/* curr_drv_state<<1; <-- das geht irgendwie nicht */ 815/* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ 816 curr_drv_state *= 2; 817 curr_drv_state |= 1; 818#ifdef GSCD_DEBUG 819 printk("DriveState: %d\n", curr_drv_state); 820#endif 821 } 822 823 ndrives = drvnum; 824 return drvnum; 825} 826 827static void __init init_cd_drive(int num) 828{ 829 char resp[50]; 830 int i; 831 832 printk("GSCD: init unit %d\n", num); 833 cc_Ident((char *) &resp); 834 835 printk("GSCD: identification: "); 836 for (i = 0; i < 0x1E; i++) { 837 printk("%c", resp[i]); 838 } 839 printk("\n"); 840 841 cc_SetSpeed(); 842 843} 844 845#ifdef FUTURE_WORK 846/* return_done */ 847static void update_state(void) 848{ 849 unsigned int AX; 850 851 852 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) { 853 if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) { 854 AX = ST_INVALID; 855 } 856 857 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) 858 == 0) { 859 invalidate(); 860 f_drv_ok = 0; 861 } 862 863 AX |= 0x8000; 864 } 865 866 if (disk_state & ST_PLAYING) { 867 AX |= 0x200; 868 } 869 870 AX |= 0x100; 871 /* pkt_esbx = AX; */ 872 873 disk_state = 0; 874 875} 876#endif 877 878static struct gendisk *gscd_disk; 879 880static void __exit gscd_exit(void) 881{ 882 CLEAR_TIMER; 883 884 del_gendisk(gscd_disk); 885 put_disk(gscd_disk); 886 if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) { 887 printk("What's that: can't unregister GoldStar-module\n"); 888 return; 889 } 890 blk_cleanup_queue(gscd_queue); 891 release_region(gscd_port, GSCD_IO_EXTENT); 892 printk(KERN_INFO "GoldStar-module released.\n"); 893} 894 895/* This is the common initialisation for the GoldStar drive. */ 896/* It is called at boot time AND for module init. */ 897static int __init gscd_init(void) 898{ 899 int i; 900 int result; 901 int ret=0; 902 903 printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION); 904 printk(KERN_INFO 905 "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", 906 gscd_port); 907 908 if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) { 909 printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already" 910 " in use.\n", gscd_port); 911 return -EIO; 912 } 913 914 915 /* check for card */ 916 result = wait_drv_ready(); 917 if (result == 0x09) { 918 printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n"); 919 ret = -EIO; 920 goto err_out1; 921 } 922 923 if (result == 0x0b) { 924 drv_mode = result; 925 i = find_drives(); 926 if (i == 0) { 927 printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is" 928 " not found.\n"); 929 ret = -EIO; 930 goto err_out1; 931 } 932 } 933 934 if ((result != 0x0b) && (result != 0x09)) { 935 printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not " 936 "exist or H/W error\n"); 937 ret = -EIO; 938 goto err_out1; 939 } 940 941 /* reset all drives */ 942 i = 0; 943 while (drv_states[i] != 0) { 944 curr_drv_state = drv_states[i]; 945 printk(KERN_INFO "GSCD: Reset unit %d ... ", i); 946 cc_Reset(); 947 printk("done\n"); 948 i++; 949 } 950 951 gscd_disk = alloc_disk(1); 952 if (!gscd_disk) 953 goto err_out1; 954 gscd_disk->major = MAJOR_NR; 955 gscd_disk->first_minor = 0; 956 gscd_disk->fops = &gscd_fops; 957 sprintf(gscd_disk->disk_name, "gscd"); 958 sprintf(gscd_disk->devfs_name, "gscd"); 959 960 if (register_blkdev(MAJOR_NR, "gscd")) { 961 ret = -EIO; 962 goto err_out2; 963 } 964 965 gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock); 966 if (!gscd_queue) { 967 ret = -ENOMEM; 968 goto err_out3; 969 } 970 971 disk_state = 0; 972 gscdPresent = 1; 973 974 gscd_disk->queue = gscd_queue; 975 add_disk(gscd_disk); 976 977 printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); 978 return 0; 979 980err_out3: 981 unregister_blkdev(MAJOR_NR, "gscd"); 982err_out2: 983 put_disk(gscd_disk); 984err_out1: 985 release_region(gscd_port, GSCD_IO_EXTENT); 986 return ret; 987} 988 989static void gscd_hsg2msf(long hsg, struct msf *msf) 990{ 991 hsg += CD_MSF_OFFSET; 992 msf->min = hsg / (CD_FRAMES * CD_SECS); 993 hsg %= CD_FRAMES * CD_SECS; 994 msf->sec = hsg / CD_FRAMES; 995 msf->frame = hsg % CD_FRAMES; 996 997 gscd_bin2bcd(&msf->min); /* convert to BCD */ 998 gscd_bin2bcd(&msf->sec); 999 gscd_bin2bcd(&msf->frame); 1000} 1001 1002 1003static void gscd_bin2bcd(unsigned char *p) 1004{ 1005 int u, t; 1006 1007 u = *p % 10; 1008 t = *p / 10; 1009 *p = u | (t << 4); 1010} 1011 1012 1013#ifdef FUTURE_WORK 1014static long gscd_msf2hsg(struct msf *mp) 1015{ 1016 return gscd_bcd2bin(mp->frame) 1017 + gscd_bcd2bin(mp->sec) * CD_FRAMES 1018 + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET; 1019} 1020 1021static int gscd_bcd2bin(unsigned char bcd) 1022{ 1023 return (bcd >> 4) * 10 + (bcd & 0xF); 1024} 1025#endif 1026 1027MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"); 1028MODULE_LICENSE("GPL"); 1029module_init(gscd_init); 1030module_exit(gscd_exit); 1031MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);