Import 2.1.118
[davej-history.git] / drivers / block / paride / pcd.c
blob4a083abbfcb14c69bc75efd88105726d3739f668
1 /*
2 pcd.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
3 Under the terms of the GNU public license.
5 This is a high-level driver for parallel port ATAPI CD-ROM
6 drives based on chips supported by the paride module.
8 By default, the driver will autoprobe for a single parallel
9 port ATAPI CD-ROM drive, but if their individual parameters are
10 specified, the driver can handle up to 4 drives.
12 The behaviour of the pcd driver can be altered by setting
13 some parameters from the insmod command line. The following
14 parameters are adjustable:
16 drive0 These four arguments can be arrays of
17 drive1 1-6 integers as follows:
18 drive2
19 drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
21 Where,
23 <prt> is the base of the parallel port address for
24 the corresponding drive. (required)
26 <pro> is the protocol number for the adapter that
27 supports this drive. These numbers are
28 logged by 'paride' when the protocol modules
29 are initialised. (0 if not given)
31 <uni> for those adapters that support chained
32 devices, this is the unit selector for the
33 chain of devices on the given port. It should
34 be zero for devices that don't support chaining.
35 (0 if not given)
37 <mod> this can be -1 to choose the best mode, or one
38 of the mode numbers supported by the adapter.
39 (-1 if not given)
41 <slv> ATAPI CD-ROMs can be jumpered to master or slave.
42 Set this to 0 to choose the master drive, 1 to
43 choose the slave, -1 (the default) to choose the
44 first drive found.
46 <dly> some parallel ports require the driver to
47 go more slowly. -1 sets a default value that
48 should work with the chosen protocol. Otherwise,
49 set this to a small integer, the larger it is
50 the slower the port i/o. In some cases, setting
51 this to zero will speed up the device. (default -1)
53 major You may use this parameter to overide the
54 default major number (46) that this driver
55 will use. Be sure to change the device
56 name as well.
58 name This parameter is a character string that
59 contains the name the kernel will use for this
60 device (in /proc output, for instance).
61 (default "pcd")
63 verbose This parameter controls the amount of logging
64 that the driver will do. Set it to 0 for
65 normal operation, 1 to see autoprobe progress
66 messages, or 2 to see additional debugging
67 output. (default 0)
69 nice This parameter controls the driver's use of
70 idle CPU time, at the expense of some speed.
72 If this driver is built into the kernel, you can use kernel
73 the following command line parameters, with the same values
74 as the corresponding module parameters listed above:
76 pcd.drive0
77 pcd.drive1
78 pcd.drive2
79 pcd.drive3
80 pcd.nice
82 In addition, you can use the parameter pcd.disable to disable
83 the driver entirely.
87 /* Changes:
89 1.01 GRG 1998.01.24 Added test unit ready support
90 1.02 GRG 1998.05.06 Changes to pcd_completion, ready_wait,
91 and loosen interpretation of ATAPI
92 standard for clearing error status.
93 Use spinlocks. Eliminate sti().
94 1.03 GRG 1998.06.16 Eliminated an Ugh
95 1.04 GRG 1998.08.15 Added extra debugging, improvements to
96 pcd_completion, use HZ in loop timing
97 1.05 GRG 1998.08.16 Conformed to "Uniform CD-ROM" standard
98 1.06 GRG 1998.08.19 Added audio ioctl support
102 #define PCD_VERSION "1.06"
103 #define PCD_MAJOR 46
104 #define PCD_NAME "pcd"
105 #define PCD_UNITS 4
107 /* Here are things one can override from the insmod command.
108 Most are autoprobed by paride unless set here. Verbose is off
109 by default.
113 static int verbose = 0;
114 static int major = PCD_MAJOR;
115 static char *name = PCD_NAME;
116 static int nice = 0;
117 static int disable = 0;
119 static int drive0[6] = {0,0,0,-1,-1,-1};
120 static int drive1[6] = {0,0,0,-1,-1,-1};
121 static int drive2[6] = {0,0,0,-1,-1,-1};
122 static int drive3[6] = {0,0,0,-1,-1,-1};
124 static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
125 static int pcd_drive_count;
127 #define D_PRT 0
128 #define D_PRO 1
129 #define D_UNI 2
130 #define D_MOD 3
131 #define D_SLV 4
132 #define D_DLY 5
134 #define DU (*drives[unit])
136 /* end of parameters */
138 #include <linux/module.h>
139 #include <linux/errno.h>
140 #include <linux/fs.h>
141 #include <linux/kernel.h>
142 #include <linux/delay.h>
143 #include <linux/cdrom.h>
145 #include <asm/uaccess.h>
146 #include <asm/spinlock.h>
148 #ifndef MODULE
150 #include "setup.h"
152 static STT pcd_stt[6] = {{"drive0",6,drive0},
153 {"drive1",6,drive1},
154 {"drive2",6,drive2},
155 {"drive3",6,drive3},
156 {"disable",1,&disable},
157 {"nice",1,&nice}};
159 void pcd_setup( char *str, int *ints)
161 { generic_setup(pcd_stt,6,str);
164 #endif
166 MODULE_PARM(verbose,"i");
167 MODULE_PARM(major,"i");
168 MODULE_PARM(name,"s");
169 MODULE_PARM(nice,"i");
170 MODULE_PARM(drive0,"1-6i");
171 MODULE_PARM(drive1,"1-6i");
172 MODULE_PARM(drive2,"1-6i");
173 MODULE_PARM(drive3,"1-6i");
175 #include "paride.h"
177 /* set up defines for blk.h, why don't all drivers do it this way ? */
179 #define MAJOR_NR major
180 #define DEVICE_NAME "PCD"
181 #define DEVICE_REQUEST do_pcd_request
182 #define DEVICE_NR(device) (MINOR(device))
183 #define DEVICE_ON(device)
184 #define DEVICE_OFF(device)
186 #include <linux/blk.h>
188 #include "pseudo.h"
190 #define PCD_RETRIES 5
191 #define PCD_TMO 800 /* timeout in jiffies */
192 #define PCD_DELAY 50 /* spin delay in uS */
193 #define PCD_READY_TMO 20 /* in seconds */
194 #define PCD_RESET_TMO 30 /* in tenths of a second */
196 #define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY)
198 #define IDE_ERR 0x01
199 #define IDE_DRQ 0x08
200 #define IDE_READY 0x40
201 #define IDE_BUSY 0x80
203 int pcd_init(void);
204 void cleanup_module( void );
206 static int pcd_open(struct cdrom_device_info *cdi, int purpose);
207 static void pcd_release(struct cdrom_device_info *cdi);
208 static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
209 static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr);
210 static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
211 static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
212 static int pcd_drive_reset(struct cdrom_device_info *cdi);
213 static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
214 static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
215 unsigned int cmd, void *arg);
217 static int pcd_detect(void);
218 static void do_pcd_read_drq(void);
219 static void do_pcd_request(void);
220 static void do_pcd_read(void);
222 static int pcd_blocksizes[PCD_UNITS];
224 struct pcd_unit {
225 struct pi_adapter pia; /* interface to paride layer */
226 struct pi_adapter *pi;
227 int drive; /* master/slave */
228 int last_sense; /* result of last request sense */
229 int changed; /* media change seen */
230 int present; /* does this unit exist ? */
231 char *name; /* pcd0, pcd1, etc */
232 struct cdrom_device_info info; /* uniform cdrom interface */
235 struct pcd_unit pcd[PCD_UNITS];
237 /* 'unit' must be defined in all functions - either as a local or a param */
239 #define PCD pcd[unit]
240 #define PI PCD.pi
242 static char pcd_scratch[64];
243 static char pcd_buffer[2048]; /* raw block buffer */
244 static int pcd_bufblk = -1; /* block in buffer, in CD units,
245 -1 for nothing there. See also
246 pd_unit.
249 /* the variables below are used mainly in the I/O request engine, which
250 processes only one request at a time.
253 static int pcd_unit = -1; /* unit of current request & bufblk */
254 static int pcd_retries; /* retries on current request */
255 static int pcd_busy = 0; /* request being processed ? */
256 static int pcd_sector; /* address of next requested sector */
257 static int pcd_count; /* number of blocks still to do */
258 static char * pcd_buf; /* buffer for request in progress */
260 static int pcd_warned = 0; /* Have we logged a phase warning ? */
262 /* kernel glue structures */
264 static struct cdrom_device_ops pcd_dops = {
265 pcd_open,
266 pcd_release,
267 pcd_drive_status,
268 pcd_media_changed,
269 pcd_tray_move,
270 pcd_lock_door,
271 0, /* select speed */
272 0, /* select disk */
273 0, /* get last session */
274 pcd_get_mcn,
275 pcd_drive_reset,
276 pcd_audio_ioctl,
277 0, /* dev_ioctl */
278 CDC_CLOSE_TRAY |
279 CDC_OPEN_TRAY |
280 CDC_LOCK |
281 CDC_MCN |
282 CDC_MEDIA_CHANGED |
283 CDC_RESET |
284 CDC_PLAY_AUDIO,
288 static void pcd_init_units( void )
290 { int unit, j;
292 pcd_drive_count = 0;
293 for (unit=0;unit<PCD_UNITS;unit++) {
294 PCD.pi = & PCD.pia;
295 PCD.present = 0;
296 PCD.last_sense = 0;
297 PCD.changed = 1;
298 PCD.drive = DU[D_SLV];
299 if (DU[D_PRT]) pcd_drive_count++;
301 j = 0;
302 while ((j < (sizeof(PCD.info.name)-2)) &&
303 (PCD.info.name[j]=name[j])) j++;
304 PCD.info.name[j++] = '0' + unit;
305 PCD.info.name[j] = 0;
306 PCD.name = &PCD.info.name[0];
308 PCD.info.ops = &pcd_dops;
309 PCD.info.handle = NULL;
310 PCD.info.dev = MKDEV(major,unit);
311 PCD.info.speed = 0;
312 PCD.info.capacity = 1;
313 PCD.info.mask = 0;
317 int pcd_init (void) /* preliminary initialisation */
319 { int i, unit;
321 if (disable) return -1;
323 pcd_init_units();
325 if (pcd_detect()) return -1;
327 if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) {
328 printk("pcd: unable to get major number %d\n",MAJOR_NR);
329 return -1;
332 for (unit=0;unit<PCD_UNITS;unit++)
333 if (PCD.present) register_cdrom(&PCD.info);
335 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
336 read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
338 for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
339 blksize_size[MAJOR_NR] = pcd_blocksizes;
341 return 0;
344 static int pcd_open(struct cdrom_device_info *cdi, int purpose)
346 { int unit = DEVICE_NR(cdi->dev);
348 if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
350 MOD_INC_USE_COUNT;
352 return 0;
355 static void pcd_release(struct cdrom_device_info *cdi)
357 { MOD_DEC_USE_COUNT;
360 #ifdef MODULE
362 /* Glue for modules ... */
364 int init_module(void)
366 { int err;
368 err = pcd_init();
370 return err;
373 void cleanup_module(void)
375 { int unit;
377 for (unit=0;unit<PCD_UNITS;unit++)
378 if (PCD.present) {
379 pi_release(PI);
380 unregister_cdrom(&PCD.info);
383 unregister_blkdev(MAJOR_NR,name);
386 #endif
388 #define WR(c,r,v) pi_write_regr(PI,c,r,v)
389 #define RR(c,r) (pi_read_regr(PI,c,r))
391 static int pcd_wait( int unit, int go, int stop, char * fun, char * msg )
393 { int j, r, e, s, p;
395 j = 0;
396 while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(j++<PCD_SPIN))
397 udelay(PCD_DELAY);
399 if ((r&(IDE_ERR&stop))||(j>=PCD_SPIN)) {
400 s = RR(0,7);
401 e = RR(0,1);
402 p = RR(0,2);
403 if (j >= PCD_SPIN) e |= 0x100;
404 if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
405 " loop=%d phase=%d\n",
406 PCD.name,fun,msg,r,s,e,j,p);
407 return (s<<8)+r;
409 return 0;
412 static int pcd_command( int unit, char * cmd, int dlen, char * fun )
414 { pi_connect(PI);
416 WR(0,6,0xa0 + 0x10*PCD.drive);
418 if (pcd_wait(unit,IDE_BUSY|IDE_DRQ,0,fun,"before command")) {
419 pi_disconnect(PI);
420 return -1;
423 WR(0,4,dlen % 256);
424 WR(0,5,dlen / 256);
425 WR(0,7,0xa0); /* ATAPI packet command */
427 if (pcd_wait(unit,IDE_BUSY,IDE_DRQ,fun,"command DRQ")) {
428 pi_disconnect(PI);
429 return -1;
432 if (RR(0,2) != 1) {
433 printk("%s: %s: command phase error\n",PCD.name,fun);
434 pi_disconnect(PI);
435 return -1;
438 pi_write_block(PI,cmd,12);
440 return 0;
443 static int pcd_completion( int unit, char * buf, char * fun )
445 { int r, d, p, n, k, j;
447 r = -1; k = 0; j = 0;
449 if (!pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
450 fun,"completion")) {
451 r = 0;
452 while (RR(0,7)&IDE_DRQ) {
453 d = (RR(0,4)+256*RR(0,5));
454 n = ((d+3)&0xfffc);
455 p = RR(0,2)&3;
457 if ((p == 2) && (n > 0) && (j == 0)) {
458 pi_read_block(PI,buf,n);
459 if (verbose > 1)
460 printk("%s: %s: Read %d bytes\n",PCD.name,fun,n);
461 r = 0; j++;
462 } else {
463 if (verbose > 1)
464 printk("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
465 PCD.name,fun,p,d,k);
466 if ((verbose < 2) && !pcd_warned) {
467 pcd_warned = 1;
468 printk("%s: WARNING: ATAPI phase errors\n",PCD.name);
470 mdelay(1);
472 if (k++ > PCD_TMO) {
473 printk("%s: Stuck DRQ\n",PCD.name);
474 break;
476 if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
477 fun,"completion")) {
478 r = -1;
479 break;
484 pi_disconnect(PI);
486 return r;
489 static void pcd_req_sense( int unit, char *fun )
491 { char rs_cmd[12] = { 0x03,0,0,0,16,0,0,0,0,0,0,0 };
492 char buf[16];
493 int r, c;
495 r = pcd_command(unit,rs_cmd,16,"Request sense");
496 mdelay(1);
497 if (!r) pcd_completion(unit,buf,"Request sense");
499 PCD.last_sense = -1; c = 2;
500 if (!r) {
501 if (fun) printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
502 PCD.name,fun,buf[2]&0xf,buf[12],buf[13]);
503 c = buf[2]&0xf;
504 PCD.last_sense = c | ((buf[12]&0xff)<<8) | ((buf[13]&0xff)<<16);
506 if ((c == 2) || (c == 6)) PCD.changed = 1;
509 static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
511 { int r;
513 r = pcd_command(unit,cmd,dlen,fun);
514 mdelay(1);
515 if (!r) r = pcd_completion(unit,buf,fun);
516 if (r) pcd_req_sense(unit,fun);
518 return r;
521 #define DBMSG(msg) ((verbose>1)?(msg):NULL)
523 static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
525 { int r;
526 int unit = DEVICE_NR(cdi->dev);
528 r = PCD.changed;
529 PCD.changed = 0;
531 return r;
534 static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
536 { char un_cmd[12] = { 0x1e,0,0,0,lock,0,0,0,0,0,0,0 };
537 int unit = DEVICE_NR(cdi->dev);
539 return pcd_atapi(unit,un_cmd,0,pcd_scratch,
540 lock?"lock door":"unlock door");
543 static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
545 { char ej_cmd[12] = { 0x1b,0,0,0,3-position,0,0,0,0,0,0,0 };
546 int unit = DEVICE_NR(cdi->dev);
548 return pcd_atapi(unit,ej_cmd,0,pcd_scratch,
549 position?"eject":"close tray");
552 static void pcd_sleep( int cs )
554 { current->state = TASK_INTERRUPTIBLE;
555 current->timeout = jiffies + cs;
556 schedule();
559 static int pcd_reset( int unit )
561 { int i, k, flg;
562 int expect[5] = {1,1,1,0x14,0xeb};
564 pi_connect(PI);
565 WR(0,6,0xa0 + 0x10*PCD.drive);
566 WR(0,7,8);
568 pcd_sleep(2); /* delay a bit */
570 k = 0;
571 while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
572 pcd_sleep(HZ/10);
574 flg = 1;
575 for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
577 if (verbose) {
578 printk("%s: Reset (%d) signature = ",PCD.name,k);
579 for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
580 if (!flg) printk(" (incorrect)");
581 printk("\n");
584 pi_disconnect(PI);
585 return flg-1;
588 static int pcd_drive_reset(struct cdrom_device_info *cdi)
590 { return pcd_reset(DEVICE_NR(cdi->dev));
593 static int pcd_ready_wait( int unit, int tmo )
595 { char tr_cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
596 int k, p;
598 k = 0;
599 while (k < tmo) {
600 PCD.last_sense = 0;
601 pcd_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready"));
602 p = PCD.last_sense;
603 if (!p) return 0;
604 if (!(((p & 0xffff) == 0x0402)||((p & 0xff) == 6))) return p;
605 k++;
606 pcd_sleep(100);
608 return 0x000020; /* timeout */
611 static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
613 { char rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0};
614 int unit = DEVICE_NR(cdi->dev);
616 if (pcd_ready_wait(unit,PCD_READY_TMO))
617 return CDS_DRIVE_NOT_READY;
618 if (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media")))
619 return CDS_NO_DISC;
620 return CDS_DISC_OK;
623 static int pcd_identify( int unit, char * id )
625 { int k, s;
626 char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
628 pcd_bufblk = -1;
630 s = pcd_atapi(unit,id_cmd,36,pcd_buffer,"identify");
632 if (s) return -1;
633 if ((pcd_buffer[0] & 0x1f) != 5) {
634 if (verbose) printk("%s: %s is not a CD-ROM\n",
635 PCD.name,PCD.drive?"Slave":"Master");
636 return -1;
638 for (k=0;k<16;k++) id[k] = pcd_buffer[16+k]; id[16] = 0;
639 k = 16; while ((k >= 0) && (id[k] <= 0x20)) { id[k] = 0; k--; }
641 printk("%s: %s: %s\n",PCD.name,PCD.drive?"Slave":"Master",id);
643 return 0;
646 static int pcd_probe( int unit, int ms, char * id )
648 /* returns 0, with id set if drive is detected
649 -1, if drive detection failed
652 { if (ms == -1) {
653 for (PCD.drive=0;PCD.drive<=1;PCD.drive++)
654 if (!pcd_reset(unit) && !pcd_identify(unit,id))
655 return 0;
656 } else {
657 PCD.drive = ms;
658 if (!pcd_reset(unit) && !pcd_identify(unit,id))
659 return 0;
661 return -1;
664 static int pcd_detect( void )
666 { char id[18];
667 int k, unit;
669 printk("%s: %s version %s, major %d, nice %d\n",
670 name,name,PCD_VERSION,major,nice);
672 k = 0;
673 if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
674 unit = 0;
675 if (pi_init(PI,1,-1,-1,-1,-1,-1,pcd_buffer,
676 PI_PCD,verbose,PCD.name)) {
677 if (!pcd_probe(unit,-1,id)) {
678 PCD.present = 1;
679 k++;
680 } else pi_release(PI);
683 } else for (unit=0;unit<PCD_UNITS;unit++) if (DU[D_PRT])
684 if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
685 DU[D_PRO],DU[D_DLY],pcd_buffer,PI_PCD,verbose,
686 PCD.name)) {
687 if (!pcd_probe(unit,DU[D_SLV],id)) {
688 PCD.present = 1;
689 k++;
690 } else pi_release(PI);
693 if (k) return 0;
695 printk("%s: No CD-ROM drive found\n",name);
696 return -1;
699 /* I/O request processing */
701 static void do_pcd_request (void)
703 { int unit;
705 if (pcd_busy) return;
706 while (1) {
707 if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
708 INIT_REQUEST;
709 if (CURRENT->cmd == READ) {
710 unit = MINOR(CURRENT->rq_dev);
711 if (unit != pcd_unit) {
712 pcd_bufblk = -1;
713 pcd_unit = unit;
715 pcd_sector = CURRENT->sector;
716 pcd_count = CURRENT->nr_sectors;
717 pcd_buf = CURRENT->buffer;
718 pcd_busy = 1;
719 ps_set_intr(do_pcd_read,0,0,nice);
720 return;
722 else end_request(0);
726 static int pcd_ready( void )
728 { int unit = pcd_unit;
730 return (((RR(1,6)&(IDE_BUSY|IDE_DRQ))==IDE_DRQ)) ;
733 static void pcd_transfer( void )
735 { int k, o;
737 while (pcd_count && (pcd_sector/4 == pcd_bufblk)) {
738 o = (pcd_sector % 4) * 512;
739 for(k=0;k<512;k++) pcd_buf[k] = pcd_buffer[o+k];
740 pcd_count--;
741 pcd_buf += 512;
742 pcd_sector++;
746 static void pcd_start( void )
748 { int unit = pcd_unit;
749 int b, i;
750 char rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
751 long saved_flags;
753 pcd_bufblk = pcd_sector / 4;
754 b = pcd_bufblk;
755 for(i=0;i<4;i++) {
756 rd_cmd[5-i] = b & 0xff;
757 b = b >> 8;
760 if (pcd_command(unit,rd_cmd,2048,"read block")) {
761 pcd_bufblk = -1;
762 spin_lock_irqsave(&io_request_lock,saved_flags);
763 pcd_busy = 0;
764 end_request(0);
765 do_pcd_request();
766 spin_unlock_irqrestore(&io_request_lock,saved_flags);
767 return;
770 mdelay(1);
772 ps_set_intr(do_pcd_read_drq,pcd_ready,PCD_TMO,nice);
776 static void do_pcd_read( void )
779 { int unit = pcd_unit;
780 long saved_flags;
782 pcd_busy = 1;
783 pcd_retries = 0;
784 pcd_transfer();
785 if (!pcd_count) {
786 spin_lock_irqsave(&io_request_lock,saved_flags);
787 end_request(1);
788 pcd_busy = 0;
789 do_pcd_request();
790 spin_unlock_irqrestore(&io_request_lock,saved_flags);
791 return;
794 pi_do_claimed(PI,pcd_start);
797 static void do_pcd_read_drq( void )
799 { int unit = pcd_unit;
800 long saved_flags;
802 if (pcd_completion(unit,pcd_buffer,"read block")) {
803 if (pcd_retries < PCD_RETRIES) {
804 mdelay(1);
805 pcd_retries++;
806 pi_do_claimed(PI,pcd_start);
807 return;
809 spin_lock_irqsave(&io_request_lock,saved_flags);
810 pcd_busy = 0;
811 pcd_bufblk = -1;
812 end_request(0);
813 do_pcd_request();
814 spin_unlock_irqrestore(&io_request_lock,saved_flags);
815 return;
818 do_pcd_read();
819 spin_lock_irqsave(&io_request_lock,saved_flags);
820 do_pcd_request();
821 spin_unlock_irqrestore(&io_request_lock,saved_flags);
824 /* the audio_ioctl stuff is adapted from sr_ioctl.c */
826 static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
827 unsigned int cmd, void *arg)
829 { int unit = DEVICE_NR(cdi->dev);
831 switch (cmd) {
833 case CDROMPAUSE:
835 { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0};
837 return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO;
840 case CDROMRESUME:
842 { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0};
844 return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO;
847 case CDROMPLAYMSF:
849 { char cmd[12]={SCMD_PLAYAUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0};
850 struct cdrom_msf* msf = (struct cdrom_msf*)arg;
852 cmd[3] = msf->cdmsf_min0;
853 cmd[4] = msf->cdmsf_sec0;
854 cmd[5] = msf->cdmsf_frame0;
855 cmd[6] = msf->cdmsf_min1;
856 cmd[7] = msf->cdmsf_sec1;
857 cmd[8] = msf->cdmsf_frame1;
859 return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO;
862 case CDROMPLAYBLK:
864 { char cmd[12]={SCMD_PLAYAUDIO10,0,0,0,0,0,0,0,0,0,0,0};
865 struct cdrom_blk* blk = (struct cdrom_blk*)arg;
867 cmd[2] = blk->from >> 24;
868 cmd[3] = blk->from >> 16;
869 cmd[4] = blk->from >> 8;
870 cmd[5] = blk->from;
871 cmd[7] = blk->len >> 8;
872 cmd[8] = blk->len;
874 return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO;
877 case CDROMPLAYTRKIND:
879 { char cmd[12]={SCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0};
880 struct cdrom_ti* ti = (struct cdrom_ti*)arg;
882 cmd[4] = ti->cdti_trk0;
883 cmd[5] = ti->cdti_ind0;
884 cmd[7] = ti->cdti_trk1;
885 cmd[8] = ti->cdti_ind1;
887 return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO;
890 case CDROMREADTOCHDR:
892 { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0};
893 struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
894 char buffer[32];
895 int r;
897 r = pcd_atapi(unit,cmd,12,buffer,"read toc header");
899 tochdr->cdth_trk0 = buffer[2];
900 tochdr->cdth_trk1 = buffer[3];
902 return r * EIO;
905 case CDROMREADTOCENTRY:
907 { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0};
909 struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
910 unsigned char buffer[32];
911 int r;
913 cmd[1] = (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
914 cmd[6] = tocentry->cdte_track;
916 r = pcd_atapi(unit,cmd,12,buffer,"read toc entry");
918 tocentry->cdte_ctrl = buffer[5] & 0xf;
919 tocentry->cdte_adr = buffer[5] >> 4;
920 tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04)?1:0;
921 if (tocentry->cdte_format == CDROM_MSF) {
922 tocentry->cdte_addr.msf.minute = buffer[9];
923 tocentry->cdte_addr.msf.second = buffer[10];
924 tocentry->cdte_addr.msf.frame = buffer[11];
925 } else
926 tocentry->cdte_addr.lba =
927 (((((buffer[8] << 8) + buffer[9]) << 8)
928 + buffer[10]) << 8) + buffer[11];
930 return r * EIO;
933 case CDROMSTOP:
935 { char cmd[12]={0x1b,1,0,0,0,0,0,0,0,0,0,0};
937 return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO;
940 case CDROMSTART:
942 { char cmd[12]={0x1b,1,0,0,1,0,0,0,0,0,0,0};
944 return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO;
947 case CDROMVOLCTRL:
949 { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0};
950 char buffer[32];
951 char mask[32];
952 struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
954 cmd[2] = 0xe;
955 cmd[4] = 28;
957 if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol"))
958 return -EIO;
960 cmd[2] = 0x4e;
962 if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask"))
963 return -EIO;
965 buffer[0] = 0;
967 buffer[21] = volctrl->channel0 & mask[21];
968 buffer[23] = volctrl->channel1 & mask[23];
969 buffer[25] = volctrl->channel2 & mask[25];
970 buffer[27] = volctrl->channel3 & mask[27];
972 cmd[0] = 0x55;
973 cmd[1] = 0x10;
975 return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO;
978 case CDROMVOLREAD:
980 { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0};
981 char buffer[32];
982 struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
983 int r;
985 cmd[2] = 0xe;
986 cmd[4] = 28;
988 r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read");
990 volctrl->channel0 = buffer[21];
991 volctrl->channel1 = buffer[23];
992 volctrl->channel2 = buffer[25];
993 volctrl->channel3 = buffer[27];
995 return r * EIO;
999 case CDROMSUBCHNL:
1001 { char cmd[12]={SCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0};
1002 struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
1003 char buffer[32];
1005 if (pcd_atapi(unit,cmd,16,buffer,"read subchannel"))
1006 return -EIO;
1008 subchnl->cdsc_audiostatus = buffer[1];
1009 subchnl->cdsc_format = CDROM_MSF;
1010 subchnl->cdsc_ctrl = buffer[5] & 0xf;
1011 subchnl->cdsc_trk = buffer[6];
1012 subchnl->cdsc_ind = buffer[7];
1014 subchnl->cdsc_reladdr.msf.minute = buffer[13];
1015 subchnl->cdsc_reladdr.msf.second = buffer[14];
1016 subchnl->cdsc_reladdr.msf.frame = buffer[15];
1017 subchnl->cdsc_absaddr.msf.minute = buffer[9];
1018 subchnl->cdsc_absaddr.msf.second = buffer[10];
1019 subchnl->cdsc_absaddr.msf.frame = buffer[11];
1021 return 0;
1024 default:
1026 return -ENOSYS;
1030 static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
1032 { char cmd[12]={SCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0};
1033 char buffer[32];
1034 int k;
1035 int unit = DEVICE_NR(cdi->dev);
1037 if (pcd_atapi(unit,cmd,24,buffer,"get mcn")) return -EIO;
1039 for (k=0;k<13;k++) mcn->medium_catalog_number[k] = buffer[k+9];
1040 mcn->medium_catalog_number[13] = 0;
1042 return 0;
1045 /* end of pcd.c */