2 * The Mitsumi CDROM interface 3 * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de> 6 ****************** H E L P ********************************* 7 * If you ever plan to update your CD ROM drive and perhaps 8 * want to sell or simply give away your Mitsumi FX-001[DS] 10 * mail me (heiko@lotte.sax.de). When my last drive goes 11 * ballistic no more driver support will be available from me !!! 12 ************************************************************* 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2, or (at your option) 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 25 * You should have received a copy of the GNU General Public License 26 * along with this program; see the file COPYING. If not, write to 27 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 30 * The Linux Community at all and ... 31 * Martin Harriss (he wrote the first Mitsumi Driver) 32 * Eberhard Moenkeberg (he gave me much support and the initial kick) 33 * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they 34 * improved the original driver) 35 * Jon Tombs, Bjorn Ekwall (module support) 36 * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) 37 * Gerd Knorr (he lent me his PhotoCD) 38 * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) 39 * Andreas Kies (testing the mysterious hang up's) 40 * ... somebody forgotten? 46 static const char*mcdx_c_version
47 ="mcdx.c,v 1.2 1996/03/22 01:14:59 heiko Exp"; 50 #include <linux/version.h> 51 #include <linux/module.h> 53 #include <linux/errno.h> 54 #include <linux/sched.h> 55 #include <linux/timer.h> 57 #include <linux/kernel.h> 58 #include <linux/cdrom.h> 59 #include <linux/ioport.h> 61 #include <linux/malloc.h> 62 #include <asm/system.h> 64 #include <asm/segment.h> 67 #include <linux/major.h> 68 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR 69 #include <linux/blk.h> 71 /* for compatible parameter passing with "insmod" */ 72 #define mcdx_drive_map mcdx 73 #include <linux/mcdx.h> 79 /* CONSTANTS *******************************************************/ 81 const int REQUEST_SIZE
=200; 82 const int DIRECT_SIZE
=200; 83 const unsigned long ACLOSE_INHIBIT
=800;/* 1/100 s of autoclose inhibit */ 85 enum drivemodes
{ TOC
, DATA
, RAW
, COOKED
}; 86 enum datamodes
{ MODE0
, MODE1
, MODE2
}; 87 enum resetmodes
{ SOFT
, HARD
}; 89 const int SINGLE
=0x01;/* single speed drive (FX001S, LU) */ 90 const int DOUBLE
=0x02;/* double speed drive (FX001D, ..? */ 91 const int DOOR
=0x04;/* door locking capability */ 92 const int MULTI
=0x08;/* multi session capability */ 94 const unsigned char READ1X
=0xc0; 95 const unsigned char READ2X
=0xc1; 98 /* DECLARATIONS ****************************************************/ 100 unsigned char minute
; 101 unsigned char second
; 106 unsigned char control
; 114 unsigned int n_first
; 116 struct s_msf msf_leadout
; 117 struct s_msf msf_first
; 122 struct s_msf msf_last
; 130 /* Per drive/controller stuff **************************************/ 132 struct s_drive_stuff
{ 134 struct wait_queue
*busyq
; 135 struct wait_queue
*lockq
; 136 struct wait_queue
*sleepq
; 139 volatileint introk
;/* status of last irq operation */ 140 volatileint busy
;/* drive performs an operation */ 141 volatileint lock
;/* exclusive usage */ 142 int eject_sw
;/* 1 - eject on last close (default 0) */ 143 int autoclose
;/* 1 - close the door on open (default 1) */ 146 struct s_diskinfo di
; 147 struct s_multi multi
; 148 struct s_subqcode
* toc
;/* first entry of the toc array */ 149 struct s_subqcode start
; 150 struct s_subqcode stop
; 151 int xa
;/* 1 if xa disk */ 152 int audio
;/* 1 if audio disk */ 155 /* `buffer' control */ 158 volatileint off_direct
; 159 volatileint off_requested
; 162 void* wreg_data
;/* w data */ 163 void* wreg_reset
;/* w hardware reset */ 164 void* wreg_hcon
;/* w hardware conf */ 165 void* wreg_chn
;/* w channel */ 166 void* rreg_data
;/* r data */ 167 void* rreg_status
;/* r status */ 169 int irq
;/* irq used by this drive */ 170 int minor
;/* minor number of this drive */ 171 int present
;/* drive present and its capabilities */ 172 unsigned char readcmd
;/* read cmd depends on single/double speed */ 173 unsigned char playcmd
;/* play should always be single speed */ 174 unsigned int xxx
;/* set if changed, reset while open */ 175 unsigned int yyy
;/* set if changed, reset by media_changed */ 176 unsigned long ejected
;/* time we called the eject function */ 177 int users
;/* keeps track of open/close */ 178 int lastsector
;/* last block accessible */ 179 int status
;/* last operation's error / status */ 180 int readerrs
;/* # of blocks read w/o error */ 184 /* Prototypes ******************************************************/ 186 /* The following prototypes are already declared elsewhere. They are 187 repeated here to show what's going on. And to sense, if they're 188 changed elsewhere. */ 190 /* declared in blk.h */ 192 voiddo_mcdx_request(void); 193 intcheck_mcdx_media_change(kdev_t
); 195 /* already declared in init/main */ 196 voidmcdx_setup(char*,int*); 198 /* Indirect exported functions. These functions are exported by their 199 addresses, such as mcdx_open and mcdx_close in the 202 /* ??? exported by the mcdx_sigaction struct */ 203 static voidmcdx_intr(int,void*,struct pt_regs
*); 205 /* exported by file_ops */ 206 static intmcdx_open(struct inode
*,struct file
*); 207 static voidmcdx_close(struct inode
*,struct file
*); 208 static intmcdx_ioctl(struct inode
*,struct file
*,unsigned int,unsigned long); 210 /* misc internal support functions */ 211 static voidlog2msf(unsigned int,struct s_msf
*); 212 static unsigned intmsf2log(const struct s_msf
*); 213 static unsigned intuint2bcd(unsigned int); 214 static unsigned intbcd2uint(unsigned char); 216 static voidTRACE((int level
,const char* fmt
, ...)); 218 static voidwarn(const char* fmt
, ...); 219 static char*port(int*); 221 static voidmcdx_delay(struct s_drive_stuff
*,long jifs
); 222 static intmcdx_transfer(struct s_drive_stuff
*,char* buf
,int sector
,int nr_sectors
); 223 static intmcdx_xfer(struct s_drive_stuff
*,char* buf
,int sector
,int nr_sectors
); 225 static intmcdx_config(struct s_drive_stuff
*,int); 226 static intmcdx_closedoor(struct s_drive_stuff
*,int); 227 static intmcdx_requestversion(struct s_drive_stuff
*,struct s_version
*,int); 228 static intmcdx_lockdoor(struct s_drive_stuff
*,int,int); 229 static intmcdx_stop(struct s_drive_stuff
*,int); 230 static intmcdx_hold(struct s_drive_stuff
*,int); 231 static intmcdx_reset(struct s_drive_stuff
*,enum resetmodes
,int); 232 static intmcdx_eject(struct s_drive_stuff
*,int); 233 static intmcdx_setdrivemode(struct s_drive_stuff
*,enum drivemodes
,int); 234 static intmcdx_setdatamode(struct s_drive_stuff
*,enum datamodes
,int); 235 static intmcdx_requestsubqcode(struct s_drive_stuff
*,struct s_subqcode
*,int); 236 static intmcdx_requestmultidiskinfo(struct s_drive_stuff
*,struct s_multi
*,int); 237 static intmcdx_requesttocdata(struct s_drive_stuff
*,struct s_diskinfo
*,int); 238 static intmcdx_getstatus(struct s_drive_stuff
*,int); 239 static intmcdx_getval(struct s_drive_stuff
*,int to
,int delay
,char*); 240 static intmcdx_talk(struct s_drive_stuff
*, 241 const unsigned char* cmd
,size_t, 242 void*buffer
,size_t size
, 243 unsigned int timeout
,int); 244 static intmcdx_readtoc(struct s_drive_stuff
*); 245 static intmcdx_playtrk(struct s_drive_stuff
*,const struct cdrom_ti
*); 246 static intmcdx_playmsf(struct s_drive_stuff
*,const struct cdrom_msf
*); 247 static intmcdx_setattentuator(struct s_drive_stuff
*,struct cdrom_volctrl
*,int); 249 /* static variables ************************************************/ 251 static int mcdx_blocksizes
[MCDX_NDRIVES
]; 252 static int mcdx_drive_map
[][2] = MCDX_DRIVEMAP
; 253 static struct s_drive_stuff
* mcdx_stuffp
[MCDX_NDRIVES
]; 254 static struct s_drive_stuff
* mcdx_irq_map
[16] = 258 static struct file_operations mcdx_fops
= { 259 NULL
,/* lseek - use kernel default */ 260 block_read
,/* read - general block-dev read */ 261 block_write
,/* write - general block-dev write */ 262 NULL
,/* no readdir */ 264 mcdx_ioctl
,/* ioctl() */ 266 mcdx_open
,/* open() */ 267 mcdx_close
,/* close() */ 270 check_mcdx_media_change
,/* media_change */ 271 NULL
/* revalidate */ 274 /* KERNEL INTERFACE FUNCTIONS **************************************/ 278 struct inode
* ip
,struct file
* fp
, 279 unsigned int cmd
,unsigned long arg
) 281 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(ip
->i_rdev
)]; 283 if(!stuffp
->present
)return-ENXIO
; 284 if(!ip
)return-EINVAL
; 288 TRACE((IOCTL
,"ioctl() START\n")); 293 TRACE((IOCTL
,"ioctl() STOP\n")); 294 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
; 295 if(-1==mcdx_stop(stuffp
,1)) 300 case CDROMPLAYTRKIND
: { 304 TRACE((IOCTL
,"ioctl() PLAYTRKIND\n")); 305 if((ans
=verify_area(VERIFY_READ
, (void*) arg
,sizeof(ti
)))) 307 memcpy_fromfs(&ti
, (void*) arg
,sizeof(ti
)); 308 if((ti
.cdti_trk0
< stuffp
->di
.n_first
) 309 || (ti
.cdti_trk0
> stuffp
->di
.n_last
) 310 || (ti
.cdti_trk1
< stuffp
->di
.n_first
)) 312 if(ti
.cdti_trk1
> stuffp
->di
.n_last
) ti
.cdti_trk1
= stuffp
->di
.n_last
; 313 TRACE((PLAYTRK
,"ioctl() track %d to %d\n", ti
.cdti_trk0
, ti
.cdti_trk1
)); 315 returnmcdx_playtrk(stuffp
, &ti
); 320 struct cdrom_msf msf
; 322 TRACE((IOCTL
,"ioctl() PLAYMSF\n")); 324 if((stuffp
->audiostatus
== CDROM_AUDIO_PLAY
) 325 && (-1==mcdx_hold(stuffp
,1)))return-EIO
; 327 if((ans
=verify_area( 328 VERIFY_READ
, (void*) arg
,sizeof(struct cdrom_msf
)))) 331 memcpy_fromfs(&msf
, (void*) arg
,sizeof msf
); 333 msf
.cdmsf_min0
=uint2bcd(msf
.cdmsf_min0
); 334 msf
.cdmsf_sec0
=uint2bcd(msf
.cdmsf_sec0
); 335 msf
.cdmsf_frame0
=uint2bcd(msf
.cdmsf_frame0
); 337 msf
.cdmsf_min1
=uint2bcd(msf
.cdmsf_min1
); 338 msf
.cdmsf_sec1
=uint2bcd(msf
.cdmsf_sec1
); 339 msf
.cdmsf_frame1
=uint2bcd(msf
.cdmsf_frame1
); 341 returnmcdx_playmsf(stuffp
, &msf
); 345 TRACE((IOCTL
,"ioctl() RESUME\n")); 346 returnmcdx_playtrk(stuffp
, NULL
); 349 case CDROMREADTOCENTRY
: { 350 struct cdrom_tocentry entry
; 351 struct s_subqcode
*tp
= NULL
; 354 TRACE((IOCTL
,"ioctl() READTOCENTRY\n")); 356 if(-1==mcdx_readtoc(stuffp
))return-1; 358 if((ans
=verify_area(VERIFY_READ
, (void*) arg
,sizeof(entry
))))return ans
; 359 memcpy_fromfs(&entry
, (void*) arg
,sizeof(entry
)); 361 if(entry
.cdte_track
== CDROM_LEADOUT
) 362 tp
= &stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+1]; 363 else if(entry
.cdte_track
> stuffp
->di
.n_last
364 || entry
.cdte_track
< stuffp
->di
.n_first
)return-EINVAL
; 365 else tp
= &stuffp
->toc
[entry
.cdte_track
- stuffp
->di
.n_first
]; 367 if(NULL
== tp
)WARN(("FATAL.\n")); 369 entry
.cdte_adr
= tp
->control
; 370 entry
.cdte_ctrl
= tp
->control
>>4; 372 if(entry
.cdte_format
== CDROM_MSF
) { 373 entry
.cdte_addr
.msf
.minute
=bcd2uint(tp
->dt
.minute
); 374 entry
.cdte_addr
.msf
.second
=bcd2uint(tp
->dt
.second
); 375 entry
.cdte_addr
.msf
.frame
=bcd2uint(tp
->dt
.frame
); 376 }else if(entry
.cdte_format
== CDROM_LBA
) 377 entry
.cdte_addr
.lba
=msf2log(&tp
->dt
); 380 if((ans
=verify_area(VERIFY_WRITE
, (void*) arg
,sizeof(entry
))))return ans
; 381 memcpy_tofs((void*) arg
, &entry
,sizeof(entry
)); 388 struct cdrom_subchnl sub
; 391 TRACE((IOCTL
,"ioctl() SUBCHNL\n")); 393 if((ans
=verify_area(VERIFY_READ
, 394 (void*) arg
,sizeof(sub
))))return ans
; 396 memcpy_fromfs(&sub
, (void*) arg
,sizeof(sub
)); 398 if(-1==mcdx_requestsubqcode(stuffp
, &q
,2))return-EIO
; 400 TRACE((SUBCHNL
,"audiostatus: %x\n", stuffp
->audiostatus
)); 401 sub
.cdsc_audiostatus
= stuffp
->audiostatus
; 402 sub
.cdsc_adr
= q
.control
; 403 sub
.cdsc_ctrl
= q
.control
>>4; 404 sub
.cdsc_trk
=bcd2uint(q
.tno
); 405 sub
.cdsc_ind
=bcd2uint(q
.index
); 407 TRACE((SUBCHNL
,"trk %d, ind %d\n", 408 sub
.cdsc_trk
, sub
.cdsc_ind
)); 410 if(sub
.cdsc_format
== CDROM_LBA
) { 411 sub
.cdsc_absaddr
.lba
=msf2log(&q
.dt
); 412 sub
.cdsc_reladdr
.lba
=msf2log(&q
.tt
); 413 TRACE((SUBCHNL
,"lba: abs %d, rel %d\n", 414 sub
.cdsc_absaddr
.lba
, 415 sub
.cdsc_reladdr
.lba
)); 416 }else if(sub
.cdsc_format
== CDROM_MSF
) { 417 sub
.cdsc_absaddr
.msf
.minute
=bcd2uint(q
.dt
.minute
); 418 sub
.cdsc_absaddr
.msf
.second
=bcd2uint(q
.dt
.second
); 419 sub
.cdsc_absaddr
.msf
.frame
=bcd2uint(q
.dt
.frame
); 420 sub
.cdsc_reladdr
.msf
.minute
=bcd2uint(q
.tt
.minute
); 421 sub
.cdsc_reladdr
.msf
.second
=bcd2uint(q
.tt
.second
); 422 sub
.cdsc_reladdr
.msf
.frame
=bcd2uint(q
.tt
.frame
); 424 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", 425 sub
.cdsc_absaddr
.msf
.minute
, 426 sub
.cdsc_absaddr
.msf
.second
, 427 sub
.cdsc_absaddr
.msf
.frame
, 428 sub
.cdsc_reladdr
.msf
.minute
, 429 sub
.cdsc_reladdr
.msf
.second
, 430 sub
.cdsc_reladdr
.msf
.frame
)); 433 if((ans
=verify_area(VERIFY_WRITE
, (void*) arg
,sizeof(sub
)))) 435 memcpy_tofs((void*) arg
, &sub
,sizeof(sub
)); 440 case CDROMREADTOCHDR
: { 441 struct cdrom_tochdr toc
; 444 TRACE((IOCTL
,"ioctl() READTOCHDR\n")); 445 if((ans
=verify_area(VERIFY_WRITE
, (void*) arg
,sizeof toc
))) 447 toc
.cdth_trk0
= stuffp
->di
.n_first
; 448 toc
.cdth_trk1
= stuffp
->di
.n_last
; 449 memcpy_tofs((void*) arg
, &toc
,sizeof toc
); 450 TRACE((TOCHDR
,"ioctl() track0 = %d, track1 = %d\n", 451 stuffp
->di
.n_first
, stuffp
->di
.n_last
)); 456 TRACE((IOCTL
,"ioctl() PAUSE\n")); 457 if(stuffp
->audiostatus
!= CDROM_AUDIO_PLAY
)return-EINVAL
; 458 if(-1==mcdx_stop(stuffp
,1))return-EIO
; 459 stuffp
->audiostatus
= CDROM_AUDIO_PAUSED
; 460 if(-1==mcdx_requestsubqcode(stuffp
, &stuffp
->start
,1)) 465 case CDROMMULTISESSION
: { 467 struct cdrom_multisession ms
; 468 TRACE((IOCTL
,"ioctl() MULTISESSION\n")); 469 if(0!= (ans
=verify_area(VERIFY_READ
, (void*) arg
, 470 sizeof(struct cdrom_multisession
)))) 473 memcpy_fromfs(&ms
, (void*) arg
,sizeof(struct cdrom_multisession
)); 474 if(ms
.addr_format
== CDROM_MSF
) { 475 ms
.addr
.msf
.minute
=bcd2uint(stuffp
->multi
.msf_last
.minute
); 476 ms
.addr
.msf
.second
=bcd2uint(stuffp
->multi
.msf_last
.second
); 477 ms
.addr
.msf
.frame
=bcd2uint(stuffp
->multi
.msf_last
.frame
); 478 }else if(ms
.addr_format
== CDROM_LBA
) 479 ms
.addr
.lba
=msf2log(&stuffp
->multi
.msf_last
); 482 ms
.xa_flag
= !!stuffp
->multi
.multi
; 484 if(0!= (ans
=verify_area(VERIFY_WRITE
, (void*) arg
, 485 sizeof(struct cdrom_multisession
)))) 488 memcpy_tofs((void*) arg
, &ms
,sizeof(struct cdrom_multisession
)); 489 if(ms
.addr_format
== CDROM_MSF
) 491 "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n", 496 stuffp
->multi
.msf_last
.minute
, 497 stuffp
->multi
.msf_last
.second
, 498 stuffp
->multi
.msf_last
.frame
)); 502 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", 505 stuffp
->multi
.msf_last
.minute
, 506 stuffp
->multi
.msf_last
.second
, 507 stuffp
->multi
.msf_last
.frame
)); 513 TRACE((IOCTL
,"ioctl() EJECT\n")); 514 if(stuffp
->users
>1)return-EBUSY
; 515 if(-1==mcdx_eject(stuffp
,1))return-EIO
; 519 case CDROMEJECT_SW
: { 520 stuffp
->eject_sw
= arg
; 526 struct cdrom_volctrl volctrl
; 528 TRACE((IOCTL
,"ioctl() VOLCTRL\n")); 529 if((ans
=verify_area( 535 memcpy_fromfs(&volctrl
, (char*) arg
,sizeof(volctrl
)); 536 returnmcdx_setattentuator(stuffp
, &volctrl
,1); 540 WARN(("ioctl(): unknown request 0x%04x\n", cmd
)); 545 voiddo_mcdx_request() 548 struct s_drive_stuff
*stuffp
; 552 TRACE((REQUEST
,"do_request()\n")); 554 if((CURRENT
== NULL
) || (CURRENT
->rq_status
== RQ_INACTIVE
)) { 555 TRACE((REQUEST
,"do_request() done\n")); 559 stuffp
= mcdx_stuffp
[MINOR(CURRENT
->rq_dev
)]; 560 TRACE((REQUEST
,"do_request() stuffp = %p\n", stuffp
)); 563 dev
=MINOR(CURRENT
->rq_dev
); 565 if((dev
<0) || (dev
>= MCDX_NDRIVES
) || (!stuffp
->present
)) { 566 WARN(("do_request(): bad device: %s\n", 567 kdevname(CURRENT
->rq_dev
))); 573 WARN(("do_request() attempt to read from audio cd\n")); 578 switch(CURRENT
->cmd
) { 580 WARN(("do_request(): attempt to write to cd!!\n")); 586 while(CURRENT
->nr_sectors
) { 589 if(-1== (i
=mcdx_transfer( 593 CURRENT
->nr_sectors
))) { 594 /*INFO(("do_request() read error\n"));*/ 595 xwarn("do_request() read error\n"); 596 if(stuffp
->status
& MCDX_ST_EOM
) { 597 CURRENT
->sector
+= CURRENT
->nr_sectors
; 598 CURRENT
->nr_sectors
=0; 600 invalidate_buffers(CURRENT
->rq_dev
); 604 CURRENT
->sector
+= i
; 605 CURRENT
->nr_sectors
-= i
; 606 CURRENT
->buffer
+= (i
*512); 614 panic(MCDX
"do_request: unknown command.\n"); 622 mcdx_open(struct inode
*ip
,struct file
*fp
) 623 /* actions done on open: 624 * 1) get the drives status */ 626 struct s_drive_stuff
*stuffp
; 628 TRACE((OPENCLOSE
,"open()\n")); 629 stuffp
= mcdx_stuffp
[MINOR(ip
->i_rdev
)]; 630 if(!stuffp
->present
)return-ENXIO
; 632 /* this is only done to test if the drive talks with us */ 633 if(-1==mcdx_getstatus(stuffp
,1))return-EIO
; 635 /* close the door, if necessary (get the door information 636 from the hardware status register). 637 If the last eject is too recent, an autoclose wouldn't probably 638 be what we want ..., if we can't read the CD after an autoclose 639 no further autocloses will be tried */ 640 if(inb((unsigned int) stuffp
->rreg_status
) & MCDX_RBIT_DOOR
) { 641 if(jiffies
- stuffp
->ejected
< ACLOSE_INHIBIT
)return-EIO
; 642 if(stuffp
->autoclose
)mcdx_closedoor(stuffp
,1); 646 /* if the media changed we will have to do a little more */ 649 TRACE((OPENCLOSE
,"open() media changed\n")); 650 /* but wait - the time of media change will be set at the 651 very last of this block - it seems, some of the following 652 talk() will detect a media change ... (I think, config() 655 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
; 657 /* get the multisession information */ 658 TRACE((OPENCLOSE
,"open() Request multisession info\n")); 659 if(-1==mcdx_requestmultidiskinfo( 660 stuffp
, &stuffp
->multi
,6)) { 661 INFO(("No multidiskinfo\n")); 662 stuffp
->autoclose
=0; 664 /* we succeeded, so on next open(2) we could try auto close 666 stuffp
->autoclose
=1; 669 if(stuffp
->multi
.multi
>2) 670 INFO(("open() unknown multisession value (%d)\n", 671 stuffp
->multi
.multi
)); 675 if(!stuffp
->multi
.multi
) 676 stuffp
->multi
.msf_last
.second
=2; 678 TRACE((OPENCLOSE
,"open() MS: %d, last @ %02x:%02x.%02x\n", 680 stuffp
->multi
.msf_last
.minute
, 681 stuffp
->multi
.msf_last
.second
, 682 stuffp
->multi
.msf_last
.frame
)); 684 }/* got multisession information */ 686 /* request the disks table of contents (aka diskinfo) */ 687 if(-1==mcdx_requesttocdata(stuffp
, &stuffp
->di
,1)) { 689 stuffp
->lastsector
= -1; 693 stuffp
->lastsector
= (CD_FRAMESIZE
/512) 694 *msf2log(&stuffp
->di
.msf_leadout
) -1; 696 TRACE((OPENCLOSE
,"open() start %d (%02x:%02x.%02x) %d\n", 698 stuffp
->di
.msf_first
.minute
, 699 stuffp
->di
.msf_first
.second
, 700 stuffp
->di
.msf_first
.frame
, 701 msf2log(&stuffp
->di
.msf_first
))); 702 TRACE((OPENCLOSE
,"open() last %d (%02x:%02x.%02x) %d\n", 704 stuffp
->di
.msf_leadout
.minute
, 705 stuffp
->di
.msf_leadout
.second
, 706 stuffp
->di
.msf_leadout
.frame
, 707 msf2log(&stuffp
->di
.msf_leadout
))); 711 TRACE((MALLOC
,"open() free old toc @ %p\n", stuffp
->toc
)); 717 TRACE((OPENCLOSE
,"open() init irq generation\n")); 718 if(-1==mcdx_config(stuffp
,1))return-EIO
; 721 /* Set the read speed */ 722 WARN(("AAA %x AAA\n", stuffp
->readcmd
)); 723 if(stuffp
->readerrs
) stuffp
->readcmd
= READ1X
; 724 else stuffp
->readcmd
= 725 stuffp
->present
| SINGLE
? READ1X
: READ2X
; 726 WARN(("XXX %x XXX\n", stuffp
->readcmd
)); 729 /* try to get the first sector, iff any ... */ 730 if(stuffp
->lastsector
>=0) { 738 for(tries
=6; tries
; tries
--) { 742 TRACE((OPENCLOSE
,"open() try as %s\n", 743 stuffp
->xa
?"XA":"normal")); 746 if(-1== (ans
=mcdx_setdatamode(stuffp
, 747 stuffp
->xa
? MODE2
: MODE1
,1))) { 753 if((stuffp
->audio
=e_audio(ans
)))break; 755 while(0== (ans
=mcdx_transfer(stuffp
, buf
,0,1))) 759 stuffp
->xa
= !stuffp
->xa
; 761 /* if (!tries) return -EIO; */ 764 /* xa disks will be read in raw mode, others not */ 765 if(-1==mcdx_setdrivemode(stuffp
, 766 stuffp
->xa
? RAW
: COOKED
,1)) 770 INFO(("open() audio disk found\n")); 771 }else if(stuffp
->lastsector
>=0) { 772 INFO(("open() %s%s disk found\n", 773 stuffp
->xa
?"XA / ":"", 774 stuffp
->multi
.multi
?"Multi Session":"Single Session")); 780 /* lock the door if not already done */ 781 if(0== stuffp
->users
&& (-1==mcdx_lockdoor(stuffp
,1,1))) 790 mcdx_close(struct inode
*ip
,struct file
*fp
) 792 struct s_drive_stuff
*stuffp
; 794 TRACE((OPENCLOSE
,"close()\n")); 796 stuffp
= mcdx_stuffp
[MINOR(ip
->i_rdev
)]; 798 if(0== --stuffp
->users
) { 799 sync_dev(ip
->i_rdev
);/* needed for r/o device? */ 801 /* invalidate_inodes(ip->i_rdev); */ 802 invalidate_buffers(ip
->i_rdev
); 806 if(-1==mcdx_lockdoor(stuffp
,0,3)) 807 INFO(("close() Cannot unlock the door\n")); 809 mcdx_lockdoor(stuffp
,0,3); 812 /* eject if wished */ 813 if(stuffp
->eject_sw
)mcdx_eject(stuffp
,1); 821 intcheck_mcdx_media_change(kdev_t full_dev
) 822 /* Return: 1 if media changed since last call to this function 825 struct s_drive_stuff
*stuffp
; 827 INFO(("check_mcdx_media_change called for device %s\n", 828 kdevname(full_dev
))); 830 stuffp
= mcdx_stuffp
[MINOR(full_dev
)]; 831 mcdx_getstatus(stuffp
,1); 833 if(stuffp
->yyy
==0)return0; 839 voidmcdx_setup(char*str
,int*pi
) 841 if(pi
[0] >0) mcdx_drive_map
[0][0] = pi
[1]; 842 if(pi
[0] >1) mcdx_drive_map
[0][1] = pi
[2]; 845 /* DIRTY PART ******************************************************/ 847 static voidmcdx_delay(struct s_drive_stuff
*stuff
,long jifs
) 848 /* This routine is used for sleeping. 849 May be we could use a simple count loop w/ jumps to itself, but 850 I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */ 852 unsigned long tout
= jiffies
+ jifs
; 855 /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */ 857 if(current
->pid
==0) {/* no sleep allowed */ 858 while(jiffies
< tout
) { 859 current
->timeout
= jiffies
; 862 }else{/* sleeping is allowed */ 863 current
->timeout
= tout
; 864 /* current->state = TASK_INTERRUPTIBLE; */ 865 /* And perhaps we should remove the while() { ... } */ 866 while(current
->timeout
) { 867 interruptible_sleep_on(&stuff
->sleepq
); 868 TRACE((SLEEP
,"delay: to is %d\n", current
->timeout
)); 874 mcdx_intr(int irq
,void*dev_id
,struct pt_regs
* regs
) 876 struct s_drive_stuff
*stuffp
; 879 stuffp
= mcdx_irq_map
[irq
]; 881 if(stuffp
== NULL
) { 882 xwarn("mcdx: no device for intr %d\n", irq
); 886 /* get the interrupt status */ 887 b
=inb((unsigned int) stuffp
->rreg_status
); 888 stuffp
->introk
= ~b
& MCDX_RBIT_DTEN
; 890 /* NOTE: We only should get interrupts if data were requested. 891 But the drive seems to generate ``asynchronous'' interrupts 892 on several error conditions too. (Despite the err int enable 893 setting during initialisation) */ 895 /* if not ok, read the next byte as the drives status */ 896 if(!stuffp
->introk
) { 897 TRACE((IRQ
,"intr() irq %d hw status 0x%02x\n", irq
, b
)); 898 if(~b
& MCDX_RBIT_STEN
) { 899 xinfo("intr() irq %d status 0x%02x\n", 900 irq
,inb((unsigned int) stuffp
->rreg_data
)); 902 xinfo("intr() irq %d ambiguous hw status\n", irq
); 905 TRACE((IRQ
,"irq() irq %d ok, status %02x\n", irq
, b
)); 909 wake_up_interruptible(&stuffp
->busyq
); 915 struct s_drive_stuff
*stuffp
, 916 const unsigned char*cmd
,size_t cmdlen
, 917 void*buffer
,size_t size
, 918 unsigned int timeout
,int tries
) 919 /* Send a command to the drive, wait for the result. 920 * returns -1 on timeout, drive status otherwise 921 * If buffer is not zero, the result (length size) is stored there. 922 * If buffer is zero the size should be the number of bytes to read 923 * from the drive. These bytes are discarded. 930 if((discard
= (buffer
== NULL
))) buffer
= &c
; 932 while(stuffp
->lock
) { 933 interruptible_sleep_on(&stuffp
->lockq
); 934 TRACE((SLEEP
,"talk: lock = %d\n", 941 #if MCDX_DEBUG & TALK 944 TRACE((TALK
,"talk() %d / %d tries, res.size %d, command 0x%02x", 945 tries
, timeout
, size
, (unsigned char) cmd
[0])); 946 for(i
=1; i
< cmdlen
; i
++)printk(" 0x%02x", cmd
[i
]); 951 /* give up if all tries are done (bad) or if the status 953 for(st
= -1; st
== -1&& tries
; tries
--) { 955 char*bp
= (char*) buffer
; 958 outsb((unsigned int) stuffp
->wreg_data
, cmd
, cmdlen
); 959 TRACE((TALK
,"talk() command sent\n")); 961 /* get the status byte */ 962 if(-1==mcdx_getval(stuffp
, timeout
,0, bp
)) { 963 INFO(("talk() %02x timed out (status), %d tr%s left\n", 964 cmd
[0], tries
-1, tries
==2?"y":"ies")); 971 TRACE((TALK
,"talk() got status 0x%02x\n", st
)); 975 WARN(("command error cmd = %02x %s\n", 976 cmd
[0], cmdlen
>1?"...":"")); 982 if(stuffp
->audiostatus
== CDROM_AUDIO_INVALID
) 983 stuffp
->audiostatus
= 984 e_audiobusy(st
) ? CDROM_AUDIO_PLAY
: CDROM_AUDIO_NO_STATUS
; 985 else if(stuffp
->audiostatus
== CDROM_AUDIO_PLAY
986 &&e_audiobusy(st
) ==0) 987 stuffp
->audiostatus
= CDROM_AUDIO_COMPLETED
; 991 INFO(("talk() media changed\n")); 992 stuffp
->xxx
= stuffp
->yyy
=1; 995 /* now actually get the data */ 997 if(-1==mcdx_getval(stuffp
, timeout
,0, bp
)) { 998 INFO(("talk() %02x timed out (data), %d tr%s left\n", 999 cmd
[0], tries
-1, tries
==2?"y":"ies")); 1003 TRACE((TALK
,"talk() got 0x%02x\n", *(bp
-1))); 1008 if(!tries
&& st
== -1)INFO(("talk() giving up\n")); 1012 wake_up_interruptible(&stuffp
->lockq
); 1014 TRACE((TALK
,"talk() done with 0x%02x\n", st
)); 1018 /* MODULE STUFF ***********************************************************/ 1021 intinit_module(void) 1027 for(i
=0; i
< MCDX_NDRIVES
; i
++) { 1028 if(mcdx_stuffp
[i
]) { 1029 TRACE((INIT
,"init_module() drive %d stuff @ %p\n", 1030 i
, mcdx_stuffp
[i
])); 1042 voidcleanup_module(void) 1046 INFO(("cleanup_module called\n")); 1048 for(i
=0; i
< MCDX_NDRIVES
; i
++) { 1049 struct s_drive_stuff
*stuffp
; 1050 stuffp
= mcdx_stuffp
[i
]; 1051 if(!stuffp
)continue; 1052 release_region((unsigned long) stuffp
->wreg_data
, MCDX_IO_SIZE
); 1053 free_irq(stuffp
->irq
, NULL
); 1055 TRACE((MALLOC
,"cleanup_module() free toc @ %p\n", stuffp
->toc
)); 1058 TRACE((MALLOC
,"cleanup_module() free stuffp @ %p\n", stuffp
)); 1059 mcdx_stuffp
[i
] = NULL
; 1063 if(unregister_blkdev(MAJOR_NR
, DEVICE_NAME
) !=0) { 1064 WARN(("cleanup() unregister_blkdev() failed\n")); 1067 elseINFO(("cleanup() succeeded\n")); 1073 /* Support functions ************************************************/ 1076 voidtrace(int level
,const char* fmt
, ...) 1081 va_start(args
, fmt
); 1082 if(sizeof(s
) <vsprintf(s
, fmt
, args
)) 1083 printk(MCDX
":: dprintf exceeds limit!!\n"); 1084 elseprintk(MCDX
":: %s", s
); 1089 voidwarn(const char* fmt
, ...) 1093 va_start(args
, fmt
); 1094 if(sizeof(s
) <vsprintf(s
, fmt
, args
)) 1095 printk(MCDX
":: dprintf exceeds limit!!\n"); 1096 elseprintk(MCDX
": %s", s
); 1105 WARN(("Version 1.9 for %s\n", kernel_version
)); 1107 WARN(("Version 1.9\n")); 1110 WARN(("mcdx.c,v 1.2 1996/03/22 01:14:59 heiko Exp\n")); 1112 /* zero the pointer array */ 1113 for(drive
=0; drive
< MCDX_NDRIVES
; drive
++) 1114 mcdx_stuffp
[drive
] = NULL
; 1116 /* do the initialisation */ 1117 for(drive
=0; drive
< MCDX_NDRIVES
; drive
++) { 1118 struct s_version version
; 1119 struct s_drive_stuff
* stuffp
; 1122 mcdx_blocksizes
[drive
] =0; 1124 size
=sizeof(*stuffp
); 1126 TRACE((INIT
,"init() try drive %d\n", drive
)); 1128 TRACE((INIT
,"kmalloc space for stuffpt's\n")); 1129 TRACE((MALLOC
,"init() malloc %d bytes\n", size
)); 1130 if(!(stuffp
=kmalloc(size
, GFP_KERNEL
))) { 1131 WARN(("init() malloc failed\n")); 1135 TRACE((INIT
,"init() got %d bytes for drive stuff @ %p\n",sizeof(*stuffp
), stuffp
)); 1137 /* set default values */ 1138 memset(stuffp
,0,sizeof(*stuffp
)); 1139 stuffp
->autoclose
=1;/* close the door on open(2) */ 1141 stuffp
->present
=0;/* this should be 0 already */ 1142 stuffp
->toc
= NULL
;/* this should be NULL already */ 1144 /* setup our irq and i/o addresses */ 1145 stuffp
->irq
=irq(mcdx_drive_map
[drive
]); 1146 stuffp
->wreg_data
= stuffp
->rreg_data
=port(mcdx_drive_map
[drive
]); 1147 stuffp
->wreg_reset
= stuffp
->rreg_status
= stuffp
->wreg_data
+1; 1148 stuffp
->wreg_hcon
= stuffp
->wreg_reset
+1; 1149 stuffp
->wreg_chn
= stuffp
->wreg_hcon
+1; 1151 /* check if i/o addresses are available */ 1152 if(0!=check_region((unsigned int) stuffp
->wreg_data
, MCDX_IO_SIZE
)) { 1154 "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n", 1155 stuffp
->wreg_data
, stuffp
->irq
, 1157 stuffp
->wreg_data
+ MCDX_IO_SIZE
-1)); 1158 TRACE((MALLOC
,"init() free stuffp @ %p\n", stuffp
)); 1160 TRACE((INIT
,"init() continue at next drive\n")); 1161 continue;/* next drive */ 1164 TRACE((INIT
,"init() i/o port is available at 0x%3p\n", stuffp
->wreg_data
)); 1166 TRACE((INIT
,"init() hardware reset\n")); 1167 mcdx_reset(stuffp
, HARD
,1); 1169 TRACE((INIT
,"init() get version\n")); 1170 if(-1==mcdx_requestversion(stuffp
, &version
,4)) { 1171 /* failed, next drive */ 1172 WARN(("%s=0x%3p,%d: Init failed. Can't get version.\n", 1174 stuffp
->wreg_data
, stuffp
->irq
)); 1175 TRACE((MALLOC
,"init() free stuffp @ %p\n", stuffp
)); 1177 TRACE((INIT
,"init() continue at next drive\n")); 1181 switch(version
.code
) { 1183 stuffp
->readcmd
= READ2X
; 1184 stuffp
->present
= DOUBLE
| DOOR
| MULTI
; 1187 stuffp
->readcmd
= READ1X
; 1188 stuffp
->present
= SINGLE
| DOOR
| MULTI
; 1191 stuffp
->readcmd
= READ1X
; 1192 stuffp
->present
= SINGLE
; 1195 stuffp
->present
=0;break; 1198 stuffp
->playcmd
= READ1X
; 1201 if(!stuffp
->present
) { 1202 WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", 1203 MCDX
, stuffp
->wreg_data
, stuffp
->irq
)); 1205 continue;/* next drive */ 1208 TRACE((INIT
,"init() register blkdev\n")); 1209 if(register_blkdev(MAJOR_NR
, DEVICE_NAME
, &mcdx_fops
) !=0) { 1210 WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n", 1212 stuffp
->wreg_data
, stuffp
->irq
, MAJOR_NR
)); 1214 continue;/* next drive */ 1217 blk_dev
[MAJOR_NR
].request_fn
= DEVICE_REQUEST
; 1218 read_ahead
[MAJOR_NR
] = READ_AHEAD
; 1220 blksize_size
[MAJOR_NR
] = mcdx_blocksizes
; 1222 TRACE((INIT
,"init() subscribe irq and i/o\n")); 1223 mcdx_irq_map
[stuffp
->irq
] = stuffp
; 1224 if(request_irq(stuffp
->irq
, mcdx_intr
, SA_INTERRUPT
, DEVICE_NAME
, NULL
)) { 1225 WARN(("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", 1227 stuffp
->wreg_data
, stuffp
->irq
, stuffp
->irq
)); 1232 request_region((unsigned int) stuffp
->wreg_data
, 1236 TRACE((INIT
,"init() get garbage\n")); 1239 mcdx_delay(stuffp
, HZ
/2); 1240 for(i
=100; i
; i
--) (void)inb((unsigned int) stuffp
->rreg_status
); 1245 outb(0x50, (unsigned int) stuffp
->wreg_chn
);/* irq 11 -> channel register */ 1248 TRACE((INIT
,"init() set non dma but irq mode\n")); 1249 mcdx_config(stuffp
,1); 1251 stuffp
->minor
= drive
; 1253 WARN((DEVICE_NAME
" installed at 0x%3p, irq %d." 1254 " (Firmware version %c %x)\n", 1255 stuffp
->wreg_data
, stuffp
->irq
, version
.code
, 1257 mcdx_stuffp
[drive
] = stuffp
; 1258 TRACE((INIT
,"init() mcdx_stuffp[%d] = %p\n", drive
, stuffp
)); 1265 mcdx_transfer(struct s_drive_stuff
*stuffp
, 1266 char*p
,int sector
,int nr_sectors
) 1267 /* This seems to do the actually transfer. But it does more. It 1268 keeps track of errors occurred and will (if possible) fall back 1269 to single speed on error. 1270 Return: -1 on timeout or other error 1271 else status byte (as in stuff->st) */ 1275 ans
=mcdx_xfer(stuffp
, p
, sector
, nr_sectors
); 1278 if(-1== ans
) stuffp
->readerrs
++; 1281 if(stuffp
->readerrs
&& stuffp
->readcmd
== READ1X
) { 1282 WARN(("XXX Already reading 1x -- no chance\n")); 1286 WARN(("XXX Fallback to 1x\n")); 1288 stuffp
->readcmd
= READ1X
; 1289 returnmcdx_transfer(stuffp
, p
, sector
, nr_sectors
); 1295 static intmcdx_xfer(struct s_drive_stuff
*stuffp
, 1296 char*p
,int sector
,int nr_sectors
) 1297 /* This does actually the transfer from the drive. 1298 Return: -1 on timeout or other error 1299 else status byte (as in stuff->st) */ 1304 TRACE((TRANSFER
,"transfer() %d sectors at sector %d\n", 1305 nr_sectors
, sector
)); 1308 WARN(("attempt to read from audio cd\n")); 1312 while(stuffp
->lock
) { 1313 interruptible_sleep_on(&stuffp
->lockq
); 1314 TRACE((SLEEP
,"xfer: lock = %d\n", 1319 && (sector
>= stuffp
->pending
) 1320 && (sector
< stuffp
->off_direct
)) { 1323 off
= stuffp
->off_requested
< (off
= sector
+ nr_sectors
) 1324 ? stuffp
->off_requested
: off
; 1326 stuffp
->lock
= current
->pid
; 1329 /* wait for the drive become idle, but first 1330 check for possible occurred errors --- the drive 1331 seems to report them asynchronously */ 1333 current
->timeout
= jiffies
+5* HZ
; 1334 while(stuffp
->introk
&& stuffp
->busy
&& current
->timeout
) { 1335 interruptible_sleep_on(&stuffp
->busyq
); 1336 TRACE((SLEEP
,"request: busy = %d, timeout = %d\n", 1337 stuffp
->busy
, current
->timeout
)); 1340 /* test for possible errors */ 1341 if(current
->timeout
==0|| !stuffp
->introk
) { 1342 if(current
->timeout
==0) { 1343 WARN(("mcdx_transfer() timeout\n")); 1344 }else if(!stuffp
->introk
) { 1345 WARN(("mcdx_transfer() error via irq reported\n")); 1347 WARN(("mcdx_transfer() unknown failure in data request\n")); 1354 wake_up_interruptible(&stuffp
->lockq
); 1355 TRACE((TRANSFER
,"transfer() done (-1)\n")); 1359 /* test if it's the first sector of a block, 1360 * there we have to skip some bytes as we read raw data */ 1361 if(stuffp
->xa
&& (0== (stuffp
->pending
&3))) { 1362 const int HEAD
= CD_FRAMESIZE_RAW
- CD_XA_TAIL
- CD_FRAMESIZE
; 1363 TRACE((TRANSFER
,"transfer() sector %d, skip %d header bytes\n", 1364 stuffp
->pending
, HEAD
)); 1365 insb((unsigned int) stuffp
->rreg_data
, p
, HEAD
); 1368 /* now actually read the data */ 1370 TRACE((TRANSFER
,"transfer() read sector %d\n", stuffp
->pending
)); 1371 insb((unsigned int) stuffp
->rreg_data
, p
,512); 1373 /* test if it's the last sector of a block, 1374 * if so, we have to expect an interrupt and to skip some 1376 if((stuffp
->busy
= (3== (stuffp
->pending
&3))) && stuffp
->xa
) { 1377 char dummy
[CD_XA_TAIL
]; 1378 TRACE((TRANSFER
,"transfer() sector %d, skip %d trailer bytes\n", 1379 stuffp
->pending
, CD_XA_TAIL
)); 1380 insb((unsigned int) stuffp
->rreg_data
, &dummy
[0], CD_XA_TAIL
); 1383 if(stuffp
->pending
== sector
) { 1388 }while(++(stuffp
->pending
) < off
); 1391 wake_up_interruptible(&stuffp
->lockq
); 1395 static unsigned char cmd
[] = { 1401 cmd
[0] = stuffp
->readcmd
; 1404 stuffp
->pending
= sector
& ~3; 1406 /* do some sanity checks */ 1407 TRACE((TRANSFER
,"transfer() request sector %d\n", stuffp
->pending
)); 1408 if(stuffp
->pending
> stuffp
->lastsector
) { 1409 WARN(("transfer() sector %d from nirvana requested.\n", 1411 stuffp
->status
= MCDX_ST_EOM
; 1413 TRACE((TRANSFER
,"transfer() done (-1)\n")); 1417 if((stuffp
->off_direct
= stuffp
->pending
+ DIRECT_SIZE
) 1418 > stuffp
->lastsector
+1) 1419 stuffp
->off_direct
= stuffp
->lastsector
+1; 1420 if((stuffp
->off_requested
= stuffp
->pending
+ REQUEST_SIZE
) 1421 > stuffp
->lastsector
+1) 1422 stuffp
->off_requested
= stuffp
->lastsector
+1; 1424 TRACE((TRANSFER
,"transfer() pending %d\n", stuffp
->pending
)); 1425 TRACE((TRANSFER
,"transfer() off_dir %d\n", stuffp
->off_direct
)); 1426 TRACE((TRANSFER
,"transfer() off_req %d\n", stuffp
->off_requested
)); 1429 struct s_msf pending
; 1430 log2msf(stuffp
->pending
/4, &pending
); 1431 cmd
[1] = pending
.minute
; 1432 cmd
[2] = pending
.second
; 1433 cmd
[3] = pending
.frame
; 1437 cmd
[6] = (unsigned char) (stuffp
->off_requested
- stuffp
->pending
) /4; 1439 outsb((unsigned int) stuffp
->wreg_data
, cmd
,sizeof cmd
); 1443 stuffp
->off_direct
= (stuffp
->off_direct
+= done
) < stuffp
->off_requested
1444 ? stuffp
->off_direct
: stuffp
->off_requested
; 1446 TRACE((TRANSFER
,"transfer() done (%d)\n", done
)); 1451 /* Access to elements of the mcdx_drive_map members */ 1453 static char*port(int*ip
) {return(char*) ip
[0]; } 1454 static intirq(int*ip
) {return ip
[1]; } 1456 /* Misc number converters */ 1458 static unsigned intbcd2uint(unsigned char c
) 1459 {return(c
>>4) *10+ (c
&0x0f); } 1461 static unsigned intuint2bcd(unsigned int ival
) 1462 {return((ival
/10) <<4) | (ival
%10); } 1464 static voidlog2msf(unsigned int l
,struct s_msf
* pmsf
) 1466 l
+= CD_BLOCK_OFFSET
; 1467 pmsf
->minute
=uint2bcd(l
/4500), l
%=4500; 1468 pmsf
->second
=uint2bcd(l
/75); 1469 pmsf
->frame
=uint2bcd(l
%75); 1472 static unsigned intmsf2log(const struct s_msf
* pmsf
) 1474 returnbcd2uint(pmsf
->frame
) 1475 +bcd2uint(pmsf
->second
) *75 1476 +bcd2uint(pmsf
->minute
) *4500 1480 intmcdx_readtoc(struct s_drive_stuff
* stuffp
) 1481 /* Read the toc entries from the CD, 1482 * Return: -1 on failure, else 0 */ 1486 TRACE((READTOC
,"ioctl() toc already read\n")); 1490 TRACE((READTOC
,"ioctl() readtoc for %d tracks\n", 1491 stuffp
->di
.n_last
- stuffp
->di
.n_first
+1)); 1493 if(-1==mcdx_hold(stuffp
,1))return-1; 1495 TRACE((READTOC
,"ioctl() tocmode\n")); 1496 if(-1==mcdx_setdrivemode(stuffp
, TOC
,1))return-EIO
; 1498 /* all seems to be ok so far ... malloc */ 1501 size
=sizeof(struct s_subqcode
) * (stuffp
->di
.n_last
- stuffp
->di
.n_first
+2); 1503 TRACE((MALLOC
,"ioctl() malloc %d bytes\n", size
)); 1504 stuffp
->toc
=kmalloc(size
, GFP_KERNEL
); 1506 WARN(("Cannot malloc %s bytes for toc\n", size
)); 1507 mcdx_setdrivemode(stuffp
, DATA
,1); 1512 /* now read actually the index */ 1518 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+1); 1520 stuffp
->toc
[trk
].index
=0; 1522 for(retries
=300; retries
; retries
--) {/* why 300? */ 1523 struct s_subqcode q
; 1526 if(-1==mcdx_requestsubqcode(stuffp
, &q
,1)) { 1527 mcdx_setdrivemode(stuffp
, DATA
,1); 1531 idx
=bcd2uint(q
.index
); 1534 && (idx
<= stuffp
->di
.n_last
) 1536 && (stuffp
->toc
[idx
- stuffp
->di
.n_first
].index
==0)) { 1537 stuffp
->toc
[idx
- stuffp
->di
.n_first
] = q
; 1538 TRACE((READTOC
,"ioctl() toc idx %d (trk %d)\n", idx
, trk
)); 1543 memset(&stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+1], 1544 0,sizeof(stuffp
->toc
[0])); 1545 stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+1].dt
1546 = stuffp
->di
.msf_leadout
; 1549 /* unset toc mode */ 1550 TRACE((READTOC
,"ioctl() undo toc mode\n")); 1551 if(-1==mcdx_setdrivemode(stuffp
, DATA
,2)) 1554 #if MCDX_DEBUG && READTOC 1557 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+2); 1559 TRACE((READTOC
,"ioctl() %d readtoc %02x %02x %02x" 1560 " %02x:%02x.%02x %02x:%02x.%02x\n", 1561 trk
+ stuffp
->di
.n_first
, 1562 stuffp
->toc
[trk
].control
, stuffp
->toc
[trk
].tno
, stuffp
->toc
[trk
].index
, 1563 stuffp
->toc
[trk
].tt
.minute
, stuffp
->toc
[trk
].tt
.second
, stuffp
->toc
[trk
].tt
.frame
, 1564 stuffp
->toc
[trk
].dt
.minute
, stuffp
->toc
[trk
].dt
.second
, stuffp
->toc
[trk
].dt
.frame
)); 1572 mcdx_playmsf(struct s_drive_stuff
* stuffp
,const struct cdrom_msf
* msf
) 1574 unsigned char cmd
[7] = { 1578 cmd
[0] = stuffp
->playcmd
; 1580 cmd
[1] = msf
->cdmsf_min0
; 1581 cmd
[2] = msf
->cdmsf_sec0
; 1582 cmd
[3] = msf
->cdmsf_frame0
; 1583 cmd
[4] = msf
->cdmsf_min1
; 1584 cmd
[5] = msf
->cdmsf_sec1
; 1585 cmd
[6] = msf
->cdmsf_frame1
; 1587 TRACE((PLAYMSF
,"ioctl(): play %x " 1588 "%02x:%02x:%02x -- %02x:%02x:%02x\n", 1589 cmd
[0], cmd
[1], cmd
[2], cmd
[3], 1590 cmd
[4], cmd
[5], cmd
[6])); 1592 outsb((unsigned int) stuffp
->wreg_data
, cmd
,sizeof cmd
); 1594 if(-1==mcdx_getval(stuffp
,3* HZ
,0, NULL
)) { 1595 WARN(("playmsf() timeout\n")); 1599 stuffp
->audiostatus
= CDROM_AUDIO_PLAY
; 1604 mcdx_playtrk(struct s_drive_stuff
* stuffp
,const struct cdrom_ti
* ti
) 1606 struct s_subqcode
* p
; 1607 struct cdrom_msf msf
; 1609 if(-1==mcdx_readtoc(stuffp
))return-1; 1611 if(ti
) p
= &stuffp
->toc
[ti
->cdti_trk0
- stuffp
->di
.n_first
]; 1612 else p
= &stuffp
->start
; 1614 msf
.cdmsf_min0
= p
->dt
.minute
; 1615 msf
.cdmsf_sec0
= p
->dt
.second
; 1616 msf
.cdmsf_frame0
= p
->dt
.frame
; 1619 p
= &stuffp
->toc
[ti
->cdti_trk1
- stuffp
->di
.n_first
+1]; 1621 }else p
= &stuffp
->stop
; 1623 msf
.cdmsf_min1
= p
->dt
.minute
; 1624 msf
.cdmsf_sec1
= p
->dt
.second
; 1625 msf
.cdmsf_frame1
= p
->dt
.frame
; 1627 returnmcdx_playmsf(stuffp
, &msf
); 1631 /* Drive functions ************************************************/ 1634 mcdx_closedoor(struct s_drive_stuff
*stuffp
,int tries
) 1636 if(stuffp
->present
& DOOR
) 1637 returnmcdx_talk(stuffp
,"\xf8",1, NULL
,1,5* HZ
, tries
); 1643 mcdx_stop(struct s_drive_stuff
*stuffp
,int tries
) 1644 {returnmcdx_talk(stuffp
,"\xf0",1, NULL
,1,2* HZ
, tries
); } 1647 mcdx_hold(struct s_drive_stuff
*stuffp
,int tries
) 1648 {returnmcdx_talk(stuffp
,"\x70",1, NULL
,1,2* HZ
, tries
); } 1651 mcdx_eject(struct s_drive_stuff
*stuffp
,int tries
) 1653 if(stuffp
->present
& DOOR
) { 1654 stuffp
->ejected
= jiffies
; 1655 returnmcdx_talk(stuffp
,"\xf6",1, NULL
,1,5* HZ
, tries
); 1660 mcdx_requestsubqcode(struct s_drive_stuff
*stuffp
, 1661 struct s_subqcode
*sub
, 1667 if(-1== (ans
=mcdx_talk( 1668 stuffp
,"\x20",1, buf
,sizeof(buf
), 1671 sub
->control
= buf
[1]; 1673 sub
->index
= buf
[3]; 1674 sub
->tt
.minute
= buf
[4]; 1675 sub
->tt
.second
= buf
[5]; 1676 sub
->tt
.frame
= buf
[6]; 1677 sub
->dt
.minute
= buf
[8]; 1678 sub
->dt
.second
= buf
[9]; 1679 sub
->dt
.frame
= buf
[10]; 1685 mcdx_requestmultidiskinfo(struct s_drive_stuff
*stuffp
,struct s_multi
*multi
,int tries
) 1690 if(stuffp
->present
& MULTI
) { 1691 ans
=mcdx_talk(stuffp
,"\x11",1, buf
,sizeof(buf
),2* HZ
, tries
); 1692 multi
->multi
= buf
[1]; 1693 multi
->msf_last
.minute
= buf
[2]; 1694 multi
->msf_last
.second
= buf
[3]; 1695 multi
->msf_last
.frame
= buf
[4]; 1704 mcdx_requesttocdata(struct s_drive_stuff
*stuffp
,struct s_diskinfo
*info
,int tries
) 1708 ans
=mcdx_talk(stuffp
,"\x10",1, buf
,sizeof(buf
),2* HZ
, tries
); 1713 info
->n_first
=bcd2uint(buf
[1]); 1714 info
->n_last
=bcd2uint(buf
[2]); 1715 info
->msf_leadout
.minute
= buf
[3]; 1716 info
->msf_leadout
.second
= buf
[4]; 1717 info
->msf_leadout
.frame
= buf
[5]; 1718 info
->msf_first
.minute
= buf
[6]; 1719 info
->msf_first
.second
= buf
[7]; 1720 info
->msf_first
.frame
= buf
[8]; 1726 mcdx_setdrivemode(struct s_drive_stuff
*stuffp
,enum drivemodes mode
,int tries
) 1731 TRACE((HW
,"setdrivemode() %d\n", mode
)); 1733 if(-1== (ans
=mcdx_talk(stuffp
,"\xc2",1, cmd
,sizeof(cmd
),5* HZ
, tries
))) 1737 case TOC
: cmd
[1] |=0x04;break; 1738 case DATA
: cmd
[1] &= ~0x04;break; 1739 case RAW
: cmd
[1] |=0x40;break; 1740 case COOKED
: cmd
[1] &= ~0x40;break; 1744 returnmcdx_talk(stuffp
, cmd
,2, NULL
,1,5* HZ
, tries
); 1748 mcdx_setdatamode(struct s_drive_stuff
*stuffp
,enum datamodes mode
,int tries
) 1750 unsigned char cmd
[2] = {0xa0}; 1751 TRACE((HW
,"setdatamode() %d\n", mode
)); 1753 case MODE0
: cmd
[1] =0x00;break; 1754 case MODE1
: cmd
[1] =0x01;break; 1755 case MODE2
: cmd
[1] =0x02;break; 1756 default:return-EINVAL
; 1758 returnmcdx_talk(stuffp
, cmd
,2, NULL
,1,5* HZ
, tries
); 1762 mcdx_config(struct s_drive_stuff
*stuffp
,int tries
) 1766 TRACE((HW
,"config()\n")); 1770 cmd
[1] =0x10;/* irq enable */ 1771 cmd
[2] =0x05;/* pre, err irq enable */ 1773 if(-1==mcdx_talk(stuffp
, cmd
,3, NULL
,1,1* HZ
, tries
)) 1776 cmd
[1] =0x02;/* dma select */ 1777 cmd
[2] =0x00;/* no dma */ 1779 returnmcdx_talk(stuffp
, cmd
,3, NULL
,1,1* HZ
, tries
); 1783 mcdx_requestversion(struct s_drive_stuff
*stuffp
,struct s_version
*ver
,int tries
) 1788 if(-1== (ans
=mcdx_talk(stuffp
,"\xdc", 1789 1, buf
,sizeof(buf
),2* HZ
, tries
))) 1799 mcdx_reset(struct s_drive_stuff
*stuffp
,enum resetmodes mode
,int tries
) 1802 outb(0, (unsigned int) stuffp
->wreg_chn
);/* no dma, no irq -> hardware */ 1803 outb(0, (unsigned int) stuffp
->wreg_reset
);/* hw reset */ 1805 }else returnmcdx_talk(stuffp
,"\x60",1, NULL
,1,5* HZ
, tries
); 1809 mcdx_lockdoor(struct s_drive_stuff
*stuffp
,int lock
,int tries
) 1811 char cmd
[2] = {0xfe}; 1812 if(stuffp
->present
& DOOR
) { 1813 cmd
[1] = lock
?0x01:0x00; 1814 returnmcdx_talk(stuffp
, cmd
,sizeof(cmd
), NULL
,1,5* HZ
, tries
); 1819 mcdx_getstatus(struct s_drive_stuff
*stuffp
,int tries
) 1820 {returnmcdx_talk(stuffp
,"\x40",1, NULL
,1,5* HZ
, tries
); } 1823 mcdx_getval(struct s_drive_stuff
*stuffp
,int to
,int delay
,char* buf
) 1825 unsigned long timeout
= to
+ jiffies
; 1830 while(inb((unsigned int) stuffp
->rreg_status
) & MCDX_RBIT_STEN
) { 1831 if(jiffies
> timeout
)return-1; 1832 mcdx_delay(stuffp
, delay
); 1835 *buf
= (unsigned char)inb((unsigned int) stuffp
->rreg_data
) &0xff; 1841 mcdx_setattentuator( 1842 struct s_drive_stuff
* stuffp
, 1843 struct cdrom_volctrl
* vol
, 1848 cmd
[1] = vol
->channel0
; 1850 cmd
[3] = vol
->channel1
; 1853 returnmcdx_talk(stuffp
, cmd
,sizeof(cmd
), NULL
,5,200, tries
); 1856 /* ex:set ts=4 sw=4: */