patch-2.1.118 linux/drivers/block/paride/pcd.c
Next file: linux/drivers/block/paride/pd.c
Previous file: linux/drivers/block/paride/paride.c
Back to the patch index
Back to the overall index
- Lines: 844
- Date:
Thu Aug 20 15:17:05 1998
- Orig file:
v2.1.117/linux/drivers/block/paride/pcd.c
- Orig date:
Mon Aug 3 12:45:44 1998
diff -u --recursive --new-file v2.1.117/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
@@ -2,11 +2,11 @@
pcd.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
Under the terms of the GNU public license.
- This is a high-level driver for parallel port ATAPI CDROM
+ This is a high-level driver for parallel port ATAPI CD-ROM
drives based on chips supported by the paride module.
By default, the driver will autoprobe for a single parallel
- port ATAPI CDROM drive, but if their individual parameters are
+ port ATAPI CD-ROM drive, but if their individual parameters are
specified, the driver can handle up to 4 drives.
The behaviour of the pcd driver can be altered by setting
@@ -38,7 +38,7 @@
of the mode numbers supported by the adapter.
(-1 if not given)
- <slv> ATAPI CDROMs can be jumpered to master or slave.
+ <slv> ATAPI CD-ROMs can be jumpered to master or slave.
Set this to 0 to choose the master drive, 1 to
choose the slave, -1 (the default) to choose the
first drive found.
@@ -61,10 +61,11 @@
(default "pcd")
verbose This parameter controls the amount of logging
- that is done while the driver probes for
- devices. Set it to 0 for a quiet load, or 1 to
- see all the progress messages. (default 0)
-
+ that the driver will do. Set it to 0 for
+ normal operation, 1 to see autoprobe progress
+ messages, or 2 to see additional debugging
+ output. (default 0)
+
nice This parameter controls the driver's use of
idle CPU time, at the expense of some speed.
@@ -85,16 +86,20 @@
/* Changes:
- 1.01 GRG 1997.01.24 Added test unit ready support
+ 1.01 GRG 1998.01.24 Added test unit ready support
1.02 GRG 1998.05.06 Changes to pcd_completion, ready_wait,
and loosen interpretation of ATAPI
standard for clearing error status.
Use spinlocks. Eliminate sti().
1.03 GRG 1998.06.16 Eliminated an Ugh
+ 1.04 GRG 1998.08.15 Added extra debugging, improvements to
+ pcd_completion, use HZ in loop timing
+ 1.05 GRG 1998.08.16 Conformed to "Uniform CD-ROM" standard
+ 1.06 GRG 1998.08.19 Added audio ioctl support
*/
-#define PCD_VERSION "1.03"
+#define PCD_VERSION "1.06"
#define PCD_MAJOR 46
#define PCD_NAME "pcd"
#define PCD_UNITS 4
@@ -185,9 +190,10 @@
#define PCD_RETRIES 5
#define PCD_TMO 800 /* timeout in jiffies */
#define PCD_DELAY 50 /* spin delay in uS */
-#define PCD_READY_TMO 20
+#define PCD_READY_TMO 20 /* in seconds */
+#define PCD_RESET_TMO 30 /* in tenths of a second */
-#define PCD_SPIN (10000/PCD_DELAY)*PCD_TMO
+#define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY)
#define IDE_ERR 0x01
#define IDE_DRQ 0x08
@@ -197,33 +203,33 @@
int pcd_init(void);
void cleanup_module( void );
-static int pcd_open(struct inode *inode, struct file *file);
-static void do_pcd_request(void);
-static void do_pcd_read(void);
-static int pcd_ioctl(struct inode *inode,struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static int pcd_release (struct inode *inode, struct file *file);
+static int pcd_open(struct cdrom_device_info *cdi, int purpose);
+static void pcd_release(struct cdrom_device_info *cdi);
+static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
+static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr);
+static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
+static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
+static int pcd_drive_reset(struct cdrom_device_info *cdi);
+static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
+static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
+ unsigned int cmd, void *arg);
static int pcd_detect(void);
-static void pcd_lock(int unit);
-static void pcd_unlock(int unit);
-static void pcd_eject(int unit);
-static int pcd_check_media(int unit);
static void do_pcd_read_drq(void);
+static void do_pcd_request(void);
+static void do_pcd_read(void);
static int pcd_blocksizes[PCD_UNITS];
-#define PCD_NAMELEN 8
-
struct pcd_unit {
- struct pi_adapter pia; /* interface to paride layer */
+ struct pi_adapter pia; /* interface to paride layer */
struct pi_adapter *pi;
- int drive; /* master/slave */
- int last_sense; /* result of last request sense */
- int access; /* count of active opens */
- int present; /* does this unit exist ? */
- char name[PCD_NAMELEN]; /* pcd0, pcd1, etc */
+ int drive; /* master/slave */
+ int last_sense; /* result of last request sense */
+ int changed; /* media change seen */
+ int present; /* does this unit exist ? */
+ char *name; /* pcd0, pcd1, etc */
+ struct cdrom_device_info info; /* uniform cdrom interface */
};
struct pcd_unit pcd[PCD_UNITS];
@@ -251,22 +257,32 @@
static int pcd_count; /* number of blocks still to do */
static char * pcd_buf; /* buffer for request in progress */
+static int pcd_warned = 0; /* Have we logged a phase warning ? */
+
/* kernel glue structures */
-static struct file_operations pcd_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- pcd_ioctl, /* ioctl */
- NULL, /* mmap */
- pcd_open, /* open */
- pcd_release, /* release */
- block_fsync, /* fsync */
- NULL, /* fasync */
- NULL, /* media change ? */
- NULL /* revalidate new media */
+static struct cdrom_device_ops pcd_dops = {
+ pcd_open,
+ pcd_release,
+ pcd_drive_status,
+ pcd_media_changed,
+ pcd_tray_move,
+ pcd_lock_door,
+ 0, /* select speed */
+ 0, /* select disk */
+ 0, /* get last session */
+ pcd_get_mcn,
+ pcd_drive_reset,
+ pcd_audio_ioctl,
+ 0, /* dev_ioctl */
+ CDC_CLOSE_TRAY |
+ CDC_OPEN_TRAY |
+ CDC_LOCK |
+ CDC_MCN |
+ CDC_MEDIA_CHANGED |
+ CDC_RESET |
+ CDC_PLAY_AUDIO,
+ 0
};
static void pcd_init_units( void )
@@ -276,21 +292,31 @@
pcd_drive_count = 0;
for (unit=0;unit<PCD_UNITS;unit++) {
PCD.pi = & PCD.pia;
- PCD.access = 0;
PCD.present = 0;
PCD.last_sense = 0;
- j = 0;
- while ((j < PCD_NAMELEN-2) && (PCD.name[j]=name[j])) j++;
- PCD.name[j++] = '0' + unit;
- PCD.name[j] = 0;
+ PCD.changed = 1;
PCD.drive = DU[D_SLV];
if (DU[D_PRT]) pcd_drive_count++;
+
+ j = 0;
+ while ((j < (sizeof(PCD.info.name)-2)) &&
+ (PCD.info.name[j]=name[j])) j++;
+ PCD.info.name[j++] = '0' + unit;
+ PCD.info.name[j] = 0;
+ PCD.name = &PCD.info.name[0];
+
+ PCD.info.ops = &pcd_dops;
+ PCD.info.handle = NULL;
+ PCD.info.dev = MKDEV(major,unit);
+ PCD.info.speed = 0;
+ PCD.info.capacity = 1;
+ PCD.info.mask = 0;
}
}
int pcd_init (void) /* preliminary initialisation */
-{ int i;
+{ int i, unit;
if (disable) return -1;
@@ -298,10 +324,14 @@
if (pcd_detect()) return -1;
- if (register_blkdev(MAJOR_NR,name,&pcd_fops)) {
+ if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) {
printk("pcd: unable to get major number %d\n",MAJOR_NR);
return -1;
}
+
+ for (unit=0;unit<PCD_UNITS;unit++)
+ if (PCD.present) register_cdrom(&PCD.info);
+
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
@@ -311,100 +341,20 @@
return 0;
}
-static int pcd_open (struct inode *inode, struct file *file)
+static int pcd_open(struct cdrom_device_info *cdi, int purpose)
-{ int unit = DEVICE_NR(inode->i_rdev);
+{ int unit = DEVICE_NR(cdi->dev);
if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
- if (file->f_mode & 2) return -EROFS; /* wants to write ? */
-
MOD_INC_USE_COUNT;
- if (pcd_check_media(unit)) {
- MOD_DEC_USE_COUNT;
- return -ENXIO;
- }
-
- pcd_lock(unit);
-
- PCD.access++;
return 0;
}
-static void do_pcd_request (void)
-
-{ int unit;
-
- if (pcd_busy) return;
- while (1) {
- if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
- INIT_REQUEST;
- if (CURRENT->cmd == READ) {
- unit = MINOR(CURRENT->rq_dev);
- if (unit != pcd_unit) {
- pcd_bufblk = -1;
- pcd_unit = unit;
- }
- pcd_sector = CURRENT->sector;
- pcd_count = CURRENT->nr_sectors;
- pcd_buf = CURRENT->buffer;
- pcd_busy = 1;
- ps_set_intr(do_pcd_read,0,0,nice);
- return;
- }
- else end_request(0);
- }
-}
-
-static int pcd_ioctl(struct inode *inode,struct file *file,
- unsigned int cmd, unsigned long arg)
-
-/* we currently support only the EJECT ioctl. */
-
-{ int unit = DEVICE_NR(inode->i_rdev);
- if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
-
- switch (cmd) {
- case CDROMEJECT: if (PCD.access == 1) {
- pcd_eject(unit);
- return 0;
- }
- default:
- return -EINVAL;
- }
-}
-
-static int pcd_release (struct inode *inode, struct file *file)
-
-{ kdev_t devp;
- int unit;
-
- struct super_block *sb;
-
- devp = inode->i_rdev;
- unit = DEVICE_NR(devp);
-
- if ((unit >= PCD_UNITS) || (PCD.access <= 0))
- return -EINVAL;
-
- PCD.access--;
-
- if (!PCD.access) {
- fsync_dev(devp);
-
- sb = get_super(devp);
- if (sb) invalidate_inodes(sb);
-
- invalidate_buffers(devp);
- pcd_unlock(unit);
-
- }
-
- MOD_DEC_USE_COUNT;
-
- return 0;
+static void pcd_release(struct cdrom_device_info *cdi)
+{ MOD_DEC_USE_COUNT;
}
#ifdef MODULE
@@ -423,11 +373,14 @@
void cleanup_module(void)
{ int unit;
-
- unregister_blkdev(MAJOR_NR,name);
for (unit=0;unit<PCD_UNITS;unit++)
- if (PCD.present) pi_release(PI);
+ if (PCD.present) {
+ pi_release(PI);
+ unregister_cdrom(&PCD.info);
+ }
+
+ unregister_blkdev(MAJOR_NR,name);
}
#endif
@@ -489,39 +442,68 @@
static int pcd_completion( int unit, char * buf, char * fun )
-{ int r, s, n;
+{ int r, d, p, n, k, j;
- r = pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,fun,"completion");
+ r = -1; k = 0; j = 0;
- if ((RR(0,2)&2) && (RR(0,7)&IDE_DRQ)) {
- n = (((RR(0,4)+256*RR(0,5))+3)&0xfffc);
- pi_read_block(PI,buf,n);
+ if (!pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
+ fun,"completion")) {
+ r = 0;
+ while (RR(0,7)&IDE_DRQ) {
+ d = (RR(0,4)+256*RR(0,5));
+ n = ((d+3)&0xfffc);
+ p = RR(0,2)&3;
+
+ if ((p == 2) && (n > 0) && (j == 0)) {
+ pi_read_block(PI,buf,n);
+ if (verbose > 1)
+ printk("%s: %s: Read %d bytes\n",PCD.name,fun,n);
+ r = 0; j++;
+ } else {
+ if (verbose > 1)
+ printk("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
+ PCD.name,fun,p,d,k);
+ if ((verbose < 2) && !pcd_warned) {
+ pcd_warned = 1;
+ printk("%s: WARNING: ATAPI phase errors\n",PCD.name);
+ }
+ mdelay(1);
+ }
+ if (k++ > PCD_TMO) {
+ printk("%s: Stuck DRQ\n",PCD.name);
+ break;
+ }
+ if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
+ fun,"completion")) {
+ r = -1;
+ break;
+ }
+ }
}
-
- s = pcd_wait(unit,IDE_BUSY,IDE_READY|IDE_ERR,fun,"data done");
-
+
pi_disconnect(PI);
- return (r?r:s);
+ return r;
}
-static void pcd_req_sense( int unit, int quiet )
+static void pcd_req_sense( int unit, char *fun )
{ char rs_cmd[12] = { 0x03,0,0,0,16,0,0,0,0,0,0,0 };
char buf[16];
- int r;
+ int r, c;
r = pcd_command(unit,rs_cmd,16,"Request sense");
mdelay(1);
if (!r) pcd_completion(unit,buf,"Request sense");
- PCD.last_sense = -1;
+ PCD.last_sense = -1; c = 2;
if (!r) {
- if (!quiet) printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
- PCD.name,buf[2]&0xf,buf[12],buf[13]);
- PCD.last_sense = (buf[2]&0xf) | ((buf[12]&0xff)<<8)
- | ((buf[13]&0xff)<<16) ;
+ if (fun) printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
+ PCD.name,fun,buf[2]&0xf,buf[12],buf[13]);
+ c = buf[2]&0xf;
+ PCD.last_sense = c | ((buf[12]&0xff)<<8) | ((buf[13]&0xff)<<16);
}
+ if ((c == 2) || (c == 6)) PCD.changed = 1;
}
static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
@@ -531,45 +513,42 @@
r = pcd_command(unit,cmd,dlen,fun);
mdelay(1);
if (!r) r = pcd_completion(unit,buf,fun);
- if (r) pcd_req_sense(unit,!fun);
+ if (r) pcd_req_sense(unit,fun);
return r;
}
-#define DBMSG(msg) NULL
+#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-static void pcd_lock(int unit)
+static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
-{ char lo_cmd[12] = { 0x1e,0,0,0,1,0,0,0,0,0,0,0 };
- char cl_cmd[12] = { 0x1b,0,0,0,3,0,0,0,0,0,0,0 };
+{ int r;
+ int unit = DEVICE_NR(cdi->dev);
- pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd1"));
- pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd2"));
- pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd3"));
- pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd4"));
- pcd_atapi(unit,cl_cmd,0,pcd_scratch,"close door");
+ r = PCD.changed;
+ PCD.changed = 0;
- pcd_atapi(unit,lo_cmd,0,pcd_scratch,DBMSG("ld"));
- pcd_atapi(unit,lo_cmd,0,pcd_scratch,"lock door");
+ return r;
}
-static void pcd_unlock( int unit )
+static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
-{ char un_cmd[12] = { 0x1e,0,0,0,0,0,0,0,0,0,0,0 };
+{ char un_cmd[12] = { 0x1e,0,0,0,lock,0,0,0,0,0,0,0 };
+ int unit = DEVICE_NR(cdi->dev);
- pcd_atapi(unit,un_cmd,0,pcd_scratch,"unlock door");
+ return pcd_atapi(unit,un_cmd,0,pcd_scratch,
+ lock?"lock door":"unlock door");
}
-static void pcd_eject( int unit)
+static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
-{ char ej_cmd[12] = { 0x1b,0,0,0,2,0,0,0,0,0,0,0 };
+{ char ej_cmd[12] = { 0x1b,0,0,0,3-position,0,0,0,0,0,0,0 };
+ int unit = DEVICE_NR(cdi->dev);
- pcd_unlock(unit);
- pcd_atapi(unit,ej_cmd,0,pcd_scratch,"eject");
+ return pcd_atapi(unit,ej_cmd,0,pcd_scratch,
+ position?"eject":"close tray");
}
-#define PCD_RESET_TMO 30 /* in tenths of a second */
-
static void pcd_sleep( int cs )
{ current->state = TASK_INTERRUPTIBLE;
@@ -579,11 +558,6 @@
static int pcd_reset( int unit )
-/* the ATAPI standard actually specifies the contents of all 7 registers
- after a reset, but the specification is ambiguous concerning the last
- two bytes, and different drives interpret the standard differently.
-*/
-
{ int i, k, flg;
int expect[5] = {1,1,1,0x14,0xeb};
@@ -591,11 +565,11 @@
WR(0,6,0xa0 + 0x10*PCD.drive);
WR(0,7,8);
- pcd_sleep(2); /* delay a bit*/
+ pcd_sleep(2); /* delay a bit */
k = 0;
while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
- pcd_sleep(10);
+ pcd_sleep(HZ/10);
flg = 1;
for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
@@ -611,6 +585,11 @@
return flg-1;
}
+static int pcd_drive_reset(struct cdrom_device_info *cdi)
+
+{ return pcd_reset(DEVICE_NR(cdi->dev));
+}
+
static int pcd_ready_wait( int unit, int tmo )
{ char tr_cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
@@ -629,12 +608,16 @@
return 0x000020; /* timeout */
}
-static int pcd_check_media( int unit )
+static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
{ char rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0};
+ int unit = DEVICE_NR(cdi->dev);
- pcd_ready_wait(unit,PCD_READY_TMO);
- return (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media")));
+ if (pcd_ready_wait(unit,PCD_READY_TMO))
+ return CDS_DRIVE_NOT_READY;
+ if (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media")))
+ return CDS_NO_DISC;
+ return CDS_DISC_OK;
}
static int pcd_identify( int unit, char * id )
@@ -648,7 +631,7 @@
if (s) return -1;
if ((pcd_buffer[0] & 0x1f) != 5) {
- if (verbose) printk("%s: %s is not a CDROM\n",
+ if (verbose) printk("%s: %s is not a CD-ROM\n",
PCD.name,PCD.drive?"Slave":"Master");
return -1;
}
@@ -709,12 +692,37 @@
if (k) return 0;
- printk("%s: No CDROM drive found\n",name);
+ printk("%s: No CD-ROM drive found\n",name);
return -1;
}
/* I/O request processing */
+static void do_pcd_request (void)
+
+{ int unit;
+
+ if (pcd_busy) return;
+ while (1) {
+ if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+ INIT_REQUEST;
+ if (CURRENT->cmd == READ) {
+ unit = MINOR(CURRENT->rq_dev);
+ if (unit != pcd_unit) {
+ pcd_bufblk = -1;
+ pcd_unit = unit;
+ }
+ pcd_sector = CURRENT->sector;
+ pcd_count = CURRENT->nr_sectors;
+ pcd_buf = CURRENT->buffer;
+ pcd_busy = 1;
+ ps_set_intr(do_pcd_read,0,0,nice);
+ return;
+ }
+ else end_request(0);
+ }
+}
+
static int pcd_ready( void )
{ int unit = pcd_unit;
@@ -793,7 +801,7 @@
if (pcd_completion(unit,pcd_buffer,"read block")) {
if (pcd_retries < PCD_RETRIES) {
- mdelay(1);
+ mdelay(1);
pcd_retries++;
pi_do_claimed(PI,pcd_start);
return;
@@ -812,6 +820,227 @@
do_pcd_request();
spin_unlock_irqrestore(&io_request_lock,saved_flags);
}
+
+/* the audio_ioctl stuff is adapted from sr_ioctl.c */
+
+static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
+ unsigned int cmd, void *arg)
+
+{ int unit = DEVICE_NR(cdi->dev);
+
+ switch (cmd) {
+
+ case CDROMPAUSE:
+
+ { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0};
+
+ return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO;
+ }
+
+ case CDROMRESUME:
+
+ { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0};
+
+ return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO;
+ }
+
+ case CDROMPLAYMSF:
+
+ { char cmd[12]={SCMD_PLAYAUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0};
+ struct cdrom_msf* msf = (struct cdrom_msf*)arg;
+
+ cmd[3] = msf->cdmsf_min0;
+ cmd[4] = msf->cdmsf_sec0;
+ cmd[5] = msf->cdmsf_frame0;
+ cmd[6] = msf->cdmsf_min1;
+ cmd[7] = msf->cdmsf_sec1;
+ cmd[8] = msf->cdmsf_frame1;
+
+ return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO;
+ }
+
+ case CDROMPLAYBLK:
+
+ { char cmd[12]={SCMD_PLAYAUDIO10,0,0,0,0,0,0,0,0,0,0,0};
+ struct cdrom_blk* blk = (struct cdrom_blk*)arg;
+
+ cmd[2] = blk->from >> 24;
+ cmd[3] = blk->from >> 16;
+ cmd[4] = blk->from >> 8;
+ cmd[5] = blk->from;
+ cmd[7] = blk->len >> 8;
+ cmd[8] = blk->len;
+
+ return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO;
+ }
+
+ case CDROMPLAYTRKIND:
+
+ { char cmd[12]={SCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0};
+ struct cdrom_ti* ti = (struct cdrom_ti*)arg;
+
+ cmd[4] = ti->cdti_trk0;
+ cmd[5] = ti->cdti_ind0;
+ cmd[7] = ti->cdti_trk1;
+ cmd[8] = ti->cdti_ind1;
+
+ return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO;
+ }
+
+ case CDROMREADTOCHDR:
+
+ { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0};
+ struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
+ char buffer[32];
+ int r;
+
+ r = pcd_atapi(unit,cmd,12,buffer,"read toc header");
+
+ tochdr->cdth_trk0 = buffer[2];
+ tochdr->cdth_trk1 = buffer[3];
+
+ return r * EIO;
+ }
+
+ case CDROMREADTOCENTRY:
+
+ { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0};
+
+ struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
+ unsigned char buffer[32];
+ int r;
+
+ cmd[1] = (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
+ cmd[6] = tocentry->cdte_track;
+
+ r = pcd_atapi(unit,cmd,12,buffer,"read toc entry");
+
+ tocentry->cdte_ctrl = buffer[5] & 0xf;
+ tocentry->cdte_adr = buffer[5] >> 4;
+ tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04)?1:0;
+ if (tocentry->cdte_format == CDROM_MSF) {
+ tocentry->cdte_addr.msf.minute = buffer[9];
+ tocentry->cdte_addr.msf.second = buffer[10];
+ tocentry->cdte_addr.msf.frame = buffer[11];
+ } else
+ tocentry->cdte_addr.lba =
+ (((((buffer[8] << 8) + buffer[9]) << 8)
+ + buffer[10]) << 8) + buffer[11];
+
+ return r * EIO;
+ }
+
+ case CDROMSTOP:
+
+ { char cmd[12]={0x1b,1,0,0,0,0,0,0,0,0,0,0};
+
+ return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO;
+ }
+
+ case CDROMSTART:
+
+ { char cmd[12]={0x1b,1,0,0,1,0,0,0,0,0,0,0};
+
+ return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO;
+ }
+
+ case CDROMVOLCTRL:
+
+ { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0};
+ char buffer[32];
+ char mask[32];
+ struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+
+ cmd[2] = 0xe;
+ cmd[4] = 28;
+
+ if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol"))
+ return -EIO;
+
+ cmd[2] = 0x4e;
+
+ if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask"))
+ return -EIO;
+
+ buffer[0] = 0;
+
+ buffer[21] = volctrl->channel0 & mask[21];
+ buffer[23] = volctrl->channel1 & mask[23];
+ buffer[25] = volctrl->channel2 & mask[25];
+ buffer[27] = volctrl->channel3 & mask[27];
+
+ cmd[0] = 0x55;
+ cmd[1] = 0x10;
+
+ return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO;
+ }
+
+ case CDROMVOLREAD:
+
+ { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0};
+ char buffer[32];
+ struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+ int r;
+
+ cmd[2] = 0xe;
+ cmd[4] = 28;
+
+ r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read");
+
+ volctrl->channel0 = buffer[21];
+ volctrl->channel1 = buffer[23];
+ volctrl->channel2 = buffer[25];
+ volctrl->channel3 = buffer[27];
+
+ return r * EIO;
+ }
+
+
+ case CDROMSUBCHNL:
+
+ { char cmd[12]={SCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0};
+ struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
+ char buffer[32];
+
+ if (pcd_atapi(unit,cmd,16,buffer,"read subchannel"))
+ return -EIO;
+
+ subchnl->cdsc_audiostatus = buffer[1];
+ subchnl->cdsc_format = CDROM_MSF;
+ subchnl->cdsc_ctrl = buffer[5] & 0xf;
+ subchnl->cdsc_trk = buffer[6];
+ subchnl->cdsc_ind = buffer[7];
+
+ subchnl->cdsc_reladdr.msf.minute = buffer[13];
+ subchnl->cdsc_reladdr.msf.second = buffer[14];
+ subchnl->cdsc_reladdr.msf.frame = buffer[15];
+ subchnl->cdsc_absaddr.msf.minute = buffer[9];
+ subchnl->cdsc_absaddr.msf.second = buffer[10];
+ subchnl->cdsc_absaddr.msf.frame = buffer[11];
+
+ return 0;
+ }
+
+ default:
+
+ return -ENOSYS;
+ }
+}
+
+static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+
+{ char cmd[12]={SCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0};
+ char buffer[32];
+ int k;
+ int unit = DEVICE_NR(cdi->dev);
+
+ if (pcd_atapi(unit,cmd,24,buffer,"get mcn")) return -EIO;
+
+ for (k=0;k<13;k++) mcn->medium_catalog_number[k] = buffer[k+9];
+ mcn->medium_catalog_number[13] = 0;
+ return 0;
+}
+
/* end of pcd.c */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov