1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103#define PCD_VERSION "1.07"
104#define PCD_MAJOR 46
105#define PCD_NAME "pcd"
106#define PCD_UNITS 4
107
108
109
110
111
112
113
114static int verbose = 0;
115static int major = PCD_MAJOR;
116static char *name = PCD_NAME;
117static int nice = 0;
118static int disable = 0;
119
120static int drive0[6] = {0,0,0,-1,-1,-1};
121static int drive1[6] = {0,0,0,-1,-1,-1};
122static int drive2[6] = {0,0,0,-1,-1,-1};
123static int drive3[6] = {0,0,0,-1,-1,-1};
124
125static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
126static int pcd_drive_count;
127
128#define D_PRT 0
129#define D_PRO 1
130#define D_UNI 2
131#define D_MOD 3
132#define D_SLV 4
133#define D_DLY 5
134
135#define DU (*drives[unit])
136
137
138
139#include <linux/module.h>
140#include <linux/errno.h>
141#include <linux/fs.h>
142#include <linux/kernel.h>
143#include <linux/delay.h>
144#include <linux/cdrom.h>
145#include <linux/spinlock.h>
146
147#include <asm/uaccess.h>
148
149#ifndef MODULE
150
151#include "setup.h"
152
153static STT pcd_stt[6] = {{"drive0",6,drive0},
154 {"drive1",6,drive1},
155 {"drive2",6,drive2},
156 {"drive3",6,drive3},
157 {"disable",1,&disable},
158 {"nice",1,&nice}};
159
160void pcd_setup( char *str, int *ints)
161
162{ generic_setup(pcd_stt,6,str);
163}
164
165#endif
166
167MODULE_PARM(verbose,"i");
168MODULE_PARM(major,"i");
169MODULE_PARM(name,"s");
170MODULE_PARM(nice,"i");
171MODULE_PARM(drive0,"1-6i");
172MODULE_PARM(drive1,"1-6i");
173MODULE_PARM(drive2,"1-6i");
174MODULE_PARM(drive3,"1-6i");
175
176#include "paride.h"
177
178
179
180#define MAJOR_NR major
181#define DEVICE_NAME "PCD"
182#define DEVICE_REQUEST do_pcd_request
183#define DEVICE_NR(device) (MINOR(device))
184#define DEVICE_ON(device)
185#define DEVICE_OFF(device)
186
187#include <linux/blk.h>
188
189#include "pseudo.h"
190
191#define PCD_RETRIES 5
192#define PCD_TMO 800
193#define PCD_DELAY 50
194#define PCD_READY_TMO 20
195#define PCD_RESET_TMO 100
196
197#define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY)
198
199#define IDE_ERR 0x01
200#define IDE_DRQ 0x08
201#define IDE_READY 0x40
202#define IDE_BUSY 0x80
203
204int pcd_init(void);
205void cleanup_module( void );
206
207static int pcd_open(struct cdrom_device_info *cdi, int purpose);
208static void pcd_release(struct cdrom_device_info *cdi);
209static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
210static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr);
211static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
212static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
213static int pcd_drive_reset(struct cdrom_device_info *cdi);
214static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
215static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
216 unsigned int cmd, void *arg);
217static int pcd_packet(struct cdrom_device_info *cdi,
218 struct cdrom_generic_command *cgc);
219
220static int pcd_detect(void);
221static void pcd_probe_capabilities(void);
222static void do_pcd_read_drq(void);
223static void do_pcd_request(request_queue_t * q);
224static void do_pcd_read(void);
225
226static int pcd_blocksizes[PCD_UNITS];
227
228struct pcd_unit {
229 struct pi_adapter pia;
230 struct pi_adapter *pi;
231 int drive;
232 int last_sense;
233 int changed;
234 int present;
235 char *name;
236 struct cdrom_device_info info;
237 };
238
239struct pcd_unit pcd[PCD_UNITS];
240
241
242
243#define PCD pcd[unit]
244#define PI PCD.pi
245
246static char pcd_scratch[64];
247static char pcd_buffer[2048];
248static int pcd_bufblk = -1;
249
250
251
252
253
254
255
256
257static int pcd_unit = -1;
258static int pcd_retries;
259static int pcd_busy = 0;
260static int pcd_sector;
261static int pcd_count;
262static char * pcd_buf;
263
264static int pcd_warned = 0;
265
266
267
268static struct block_device_operations pcd_bdops = {
269 owner: THIS_MODULE,
270 open: cdrom_open,
271 release: cdrom_release,
272 ioctl: cdrom_ioctl,
273 check_media_change: cdrom_media_changed,
274};
275
276static struct cdrom_device_ops pcd_dops = {
277 pcd_open,
278 pcd_release,
279 pcd_drive_status,
280 pcd_media_changed,
281 pcd_tray_move,
282 pcd_lock_door,
283 0,
284 0,
285 0,
286 pcd_get_mcn,
287 pcd_drive_reset,
288 pcd_audio_ioctl,
289 0,
290 CDC_CLOSE_TRAY |
291 CDC_OPEN_TRAY |
292 CDC_LOCK |
293 CDC_MCN |
294 CDC_MEDIA_CHANGED |
295 CDC_RESET |
296 CDC_PLAY_AUDIO |
297 CDC_GENERIC_PACKET |
298 CDC_CD_R |
299 CDC_CD_RW,
300 0,
301 pcd_packet,
302};
303
304static void pcd_init_units( void )
305
306{ int unit, j;
307
308 pcd_drive_count = 0;
309 for (unit=0;unit<PCD_UNITS;unit++) {
310 PCD.pi = & PCD.pia;
311 PCD.present = 0;
312 PCD.last_sense = 0;
313 PCD.changed = 1;
314 PCD.drive = DU[D_SLV];
315 if (DU[D_PRT]) pcd_drive_count++;
316
317 j = 0;
318 while ((j < (sizeof(PCD.info.name)-2)) &&
319 (PCD.info.name[j]=name[j])) j++;
320 PCD.info.name[j++] = '0' + unit;
321 PCD.info.name[j] = 0;
322 PCD.name = &PCD.info.name[0];
323
324 PCD.info.ops = &pcd_dops;
325 PCD.info.handle = NULL;
326 PCD.info.dev = MKDEV(major,unit);
327 PCD.info.speed = 0;
328 PCD.info.capacity = 1;
329 PCD.info.mask = 0;
330 }
331}
332
333int pcd_init (void)
334
335{ int i, unit;
336
337 if (disable) return -1;
338
339 pcd_init_units();
340
341 if (pcd_detect()) return -1;
342
343
344 pcd_probe_capabilities();
345
346 if (register_blkdev(MAJOR_NR,name,&pcd_bdops)) {
347 printk("pcd: unable to get major number %d\n",MAJOR_NR);
348 return -1;
349 }
350
351 for (unit=0;unit<PCD_UNITS;unit++) {
352 if (PCD.present) {
353 register_cdrom(&PCD.info);
354 devfs_plain_cdrom(&PCD.info, &pcd_bdops);
355 }
356 }
357
358 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
359 read_ahead[MAJOR_NR] = 8;
360
361 for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
362 blksize_size[MAJOR_NR] = pcd_blocksizes;
363
364 return 0;
365}
366
367static int pcd_open(struct cdrom_device_info *cdi, int purpose)
368
369{ int unit = DEVICE_NR(cdi->dev);
370
371 if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
372
373 return 0;
374}
375
376static void pcd_release(struct cdrom_device_info *cdi)
377
378{
379}
380
381#ifdef MODULE
382
383
384
385int init_module(void)
386
387{ int err;
388
389#ifdef PARIDE_JUMBO
390 { extern paride_init();
391 paride_init();
392 }
393#endif
394
395 err = pcd_init();
396
397 return err;
398}
399
400void cleanup_module(void)
401
402{ int unit;
403
404 for (unit=0;unit<PCD_UNITS;unit++)
405 if (PCD.present) {
406 pi_release(PI);
407 unregister_cdrom(&PCD.info);
408 }
409
410 unregister_blkdev(MAJOR_NR,name);
411}
412
413#endif
414
415#define WR(c,r,v) pi_write_regr(PI,c,r,v)
416#define RR(c,r) (pi_read_regr(PI,c,r))
417
418static int pcd_wait( int unit, int go, int stop, char * fun, char * msg )
419
420{ int j, r, e, s, p;
421
422 j = 0;
423 while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(j++<PCD_SPIN))
424 udelay(PCD_DELAY);
425
426 if ((r&(IDE_ERR&stop))||(j>=PCD_SPIN)) {
427 s = RR(0,7);
428 e = RR(0,1);
429 p = RR(0,2);
430 if (j >= PCD_SPIN) e |= 0x100;
431 if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
432 " loop=%d phase=%d\n",
433 PCD.name,fun,msg,r,s,e,j,p);
434 return (s<<8)+r;
435 }
436 return 0;
437}
438
439static int pcd_command( int unit, char * cmd, int dlen, char * fun )
440
441{ pi_connect(PI);
442
443 WR(0,6,0xa0 + 0x10*PCD.drive);
444
445 if (pcd_wait(unit,IDE_BUSY|IDE_DRQ,0,fun,"before command")) {
446 pi_disconnect(PI);
447 return -1;
448 }
449
450 WR(0,4,dlen % 256);
451 WR(0,5,dlen / 256);
452 WR(0,7,0xa0);
453
454 if (pcd_wait(unit,IDE_BUSY,IDE_DRQ,fun,"command DRQ")) {
455 pi_disconnect(PI);
456 return -1;
457 }
458
459 if (RR(0,2) != 1) {
460 printk("%s: %s: command phase error\n",PCD.name,fun);
461 pi_disconnect(PI);
462 return -1;
463 }
464
465 pi_write_block(PI,cmd,12);
466
467 return 0;
468}
469
470static int pcd_completion( int unit, char * buf, char * fun )
471
472{ int r, d, p, n, k, j;
473
474 r = -1; k = 0; j = 0;
475
476 if (!pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
477 fun,"completion")) {
478 r = 0;
479 while (RR(0,7)&IDE_DRQ) {
480 d = (RR(0,4)+256*RR(0,5));
481 n = ((d+3)&0xfffc);
482 p = RR(0,2)&3;
483
484 if ((p == 2) && (n > 0) && (j == 0)) {
485 pi_read_block(PI,buf,n);
486 if (verbose > 1)
487 printk("%s: %s: Read %d bytes\n",PCD.name,fun,n);
488 r = 0; j++;
489 } else {
490 if (verbose > 1)
491 printk("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
492 PCD.name,fun,p,d,k);
493 if ((verbose < 2) && !pcd_warned) {
494 pcd_warned = 1;
495 printk("%s: WARNING: ATAPI phase errors\n",PCD.name);
496 }
497 mdelay(1);
498 }
499 if (k++ > PCD_TMO) {
500 printk("%s: Stuck DRQ\n",PCD.name);
501 break;
502 }
503 if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
504 fun,"completion")) {
505 r = -1;
506 break;
507 }
508 }
509 }
510
511 pi_disconnect(PI);
512
513 return r;
514}
515
516static void pcd_req_sense( int unit, char *fun )
517
518{ char rs_cmd[12] = { 0x03,0,0,0,16,0,0,0,0,0,0,0 };
519 char buf[16];
520 int r, c;
521
522 r = pcd_command(unit,rs_cmd,16,"Request sense");
523 mdelay(1);
524 if (!r) pcd_completion(unit,buf,"Request sense");
525
526 PCD.last_sense = -1; c = 2;
527 if (!r) {
528 if (fun) printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
529 PCD.name,fun,buf[2]&0xf,buf[12],buf[13]);
530 c = buf[2]&0xf;
531 PCD.last_sense = c | ((buf[12]&0xff)<<8) | ((buf[13]&0xff)<<16);
532 }
533 if ((c == 2) || (c == 6)) PCD.changed = 1;
534}
535
536static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
537
538{ int r;
539
540 r = pcd_command(unit,cmd,dlen,fun);
541 mdelay(1);
542 if (!r) r = pcd_completion(unit,buf,fun);
543 if (r) pcd_req_sense(unit,fun);
544
545 return r;
546}
547
548static int pcd_packet(struct cdrom_device_info *cdi,
549 struct cdrom_generic_command *cgc)
550{
551 char *un_cmd;
552 int unit = DEVICE_NR(cdi->dev);
553
554 un_cmd = cgc->cmd;
555 return pcd_atapi(unit,un_cmd,cgc->buflen,cgc->buffer, "generic packet");
556}
557
558#define DBMSG(msg) ((verbose>1)?(msg):NULL)
559
560static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
561
562{ int r;
563 int unit = DEVICE_NR(cdi->dev);
564
565 r = PCD.changed;
566 PCD.changed = 0;
567
568 return r;
569}
570
571static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
572
573{ char un_cmd[12] = { 0x1e,0,0,0,lock,0,0,0,0,0,0,0 };
574 int unit = DEVICE_NR(cdi->dev);
575
576 return pcd_atapi(unit,un_cmd,0,pcd_scratch,
577 lock?"lock door":"unlock door");
578}
579
580static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
581
582{ char ej_cmd[12] = { 0x1b,0,0,0,3-position,0,0,0,0,0,0,0 };
583 int unit = DEVICE_NR(cdi->dev);
584
585 return pcd_atapi(unit,ej_cmd,0,pcd_scratch,
586 position?"eject":"close tray");
587}
588
589static void pcd_sleep( int cs )
590
591{ current->state = TASK_INTERRUPTIBLE;
592 schedule_timeout(cs);
593}
594
595static int pcd_reset( int unit )
596
597{ int i, k, flg;
598 int expect[5] = {1,1,1,0x14,0xeb};
599
600 pi_connect(PI);
601 WR(0,6,0xa0 + 0x10*PCD.drive);
602 WR(0,7,8);
603
604 pcd_sleep(20*HZ/1000);
605
606 k = 0;
607 while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
608 pcd_sleep(HZ/10);
609
610 flg = 1;
611 for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
612
613 if (verbose) {
614 printk("%s: Reset (%d) signature = ",PCD.name,k);
615 for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
616 if (!flg) printk(" (incorrect)");
617 printk("\n");
618 }
619
620 pi_disconnect(PI);
621 return flg-1;
622}
623
624static int pcd_drive_reset(struct cdrom_device_info *cdi)
625
626{ return pcd_reset(DEVICE_NR(cdi->dev));
627}
628
629static int pcd_ready_wait( int unit, int tmo )
630
631{ char tr_cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
632 int k, p;
633
634 k = 0;
635 while (k < tmo) {
636 PCD.last_sense = 0;
637 pcd_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready"));
638 p = PCD.last_sense;
639 if (!p) return 0;
640 if (!(((p & 0xffff) == 0x0402)||((p & 0xff) == 6))) return p;
641 k++;
642 pcd_sleep(HZ);
643 }
644 return 0x000020;
645}
646
647static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
648
649{ char rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0};
650 int unit = DEVICE_NR(cdi->dev);
651
652 if (pcd_ready_wait(unit,PCD_READY_TMO))
653 return CDS_DRIVE_NOT_READY;
654 if (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media")))
655 return CDS_NO_DISC;
656 return CDS_DISC_OK;
657}
658
659static int pcd_identify( int unit, char * id )
660
661{ int k, s;
662 char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
663
664 pcd_bufblk = -1;
665
666 s = pcd_atapi(unit,id_cmd,36,pcd_buffer,"identify");
667
668 if (s) return -1;
669 if ((pcd_buffer[0] & 0x1f) != 5) {
670 if (verbose) printk("%s: %s is not a CD-ROM\n",
671 PCD.name,PCD.drive?"Slave":"Master");
672 return -1;
673 }
674 for (k=0;k<16;k++) id[k] = pcd_buffer[16+k]; id[16] = 0;
675 k = 16; while ((k >= 0) && (id[k] <= 0x20)) { id[k] = 0; k--; }
676
677 printk("%s: %s: %s\n",PCD.name,PCD.drive?"Slave":"Master",id);
678
679 return 0;
680}
681
682static int pcd_probe( int unit, int ms, char * id )
683
684
685
686
687
688{ if (ms == -1) {
689 for (PCD.drive=0;PCD.drive<=1;PCD.drive++)
690 if (!pcd_reset(unit) && !pcd_identify(unit,id))
691 return 0;
692 } else {
693 PCD.drive = ms;
694 if (!pcd_reset(unit) && !pcd_identify(unit,id))
695 return 0;
696 }
697 return -1;
698}
699
700static void pcd_probe_capabilities( void )
701
702{ int unit, r;
703 char buffer[32];
704 char cmd[12]={0x5a,1<<3,0x2a,0,0,0,0,18,0,0,0,0};
705
706 for (unit=0;unit<PCD_UNITS;unit++) {
707 if (!PCD.present) continue;
708 r = pcd_atapi(unit,cmd,18, buffer,"mode sense capabilities");
709 if (r) continue;
710
711 if ((buffer[11] & 1) == 0)
712 PCD.info.mask |= CDC_CD_R;
713 if ((buffer[11] & 2) == 0)
714 PCD.info.mask |= CDC_CD_RW;
715 if ((buffer[12] & 1) == 0)
716 PCD.info.mask |= CDC_PLAY_AUDIO;
717 if ((buffer[14] & 1) == 0)
718 PCD.info.mask |= CDC_LOCK;
719 if ((buffer[14] & 8) == 0)
720 PCD.info.mask |= CDC_OPEN_TRAY;
721 if ((buffer[14] >> 6) == 0)
722 PCD.info.mask |= CDC_CLOSE_TRAY;
723 }
724}
725
726static int pcd_detect( void )
727
728{ char id[18];
729 int k, unit;
730
731 printk("%s: %s version %s, major %d, nice %d\n",
732 name,name,PCD_VERSION,major,nice);
733
734 k = 0;
735 if (pcd_drive_count == 0) {
736 unit = 0;
737 if (pi_init(PI,1,-1,-1,-1,-1,-1,pcd_buffer,
738 PI_PCD,verbose,PCD.name)) {
739 if (!pcd_probe(unit,-1,id)) {
740 PCD.present = 1;
741 k++;
742 } else pi_release(PI);
743 }
744
745 } else for (unit=0;unit<PCD_UNITS;unit++) if (DU[D_PRT])
746 if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
747 DU[D_PRO],DU[D_DLY],pcd_buffer,PI_PCD,verbose,
748 PCD.name)) {
749 if (!pcd_probe(unit,DU[D_SLV],id)) {
750 PCD.present = 1;
751 k++;
752 } else pi_release(PI);
753 }
754
755 if (k) return 0;
756
757 printk("%s: No CD-ROM drive found\n",name);
758 return -1;
759}
760
761
762
763static void do_pcd_request (request_queue_t * q)
764
765{ int unit;
766
767 if (pcd_busy) return;
768 while (1) {
769 if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return;
770 INIT_REQUEST;
771 if (CURRENT->cmd == READ) {
772 unit = MINOR(CURRENT->rq_dev);
773 if (unit != pcd_unit) {
774 pcd_bufblk = -1;
775 pcd_unit = unit;
776 }
777 pcd_sector = CURRENT->sector;
778 pcd_count = CURRENT->current_nr_sectors;
779 pcd_buf = CURRENT->buffer;
780 pcd_busy = 1;
781 ps_set_intr(do_pcd_read,0,0,nice);
782 return;
783 }
784 else end_request(0);
785 }
786}
787
788static int pcd_ready( void )
789
790{ int unit = pcd_unit;
791
792 return (((RR(1,6)&(IDE_BUSY|IDE_DRQ))==IDE_DRQ)) ;
793}
794
795static void pcd_transfer( void )
796
797{ int k, o;
798
799 while (pcd_count && (pcd_sector/4 == pcd_bufblk)) {
800 o = (pcd_sector % 4) * 512;
801 for(k=0;k<512;k++) pcd_buf[k] = pcd_buffer[o+k];
802 pcd_count--;
803 pcd_buf += 512;
804 pcd_sector++;
805 }
806}
807
808static void pcd_start( void )
809
810{ int unit = pcd_unit;
811 int b, i;
812 char rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
813 unsigned long saved_flags;
814
815 pcd_bufblk = pcd_sector / 4;
816 b = pcd_bufblk;
817 for(i=0;i<4;i++) {
818 rd_cmd[5-i] = b & 0xff;
819 b = b >> 8;
820 }
821
822 if (pcd_command(unit,rd_cmd,2048,"read block")) {
823 pcd_bufblk = -1;
824 spin_lock_irqsave(&io_request_lock,saved_flags);
825 pcd_busy = 0;
826 end_request(0);
827 do_pcd_request(NULL);
828 spin_unlock_irqrestore(&io_request_lock,saved_flags);
829 return;
830 }
831
832 mdelay(1);
833
834 ps_set_intr(do_pcd_read_drq,pcd_ready,PCD_TMO,nice);
835
836}
837
838static void do_pcd_read( void )
839
840
841{ int unit = pcd_unit;
842 unsigned long saved_flags;
843
844 pcd_busy = 1;
845 pcd_retries = 0;
846 pcd_transfer();
847 if (!pcd_count) {
848 spin_lock_irqsave(&io_request_lock,saved_flags);
849 end_request(1);
850 pcd_busy = 0;
851 do_pcd_request(NULL);
852 spin_unlock_irqrestore(&io_request_lock,saved_flags);
853 return;
854 }
855
856 pi_do_claimed(PI,pcd_start);
857}
858
859static void do_pcd_read_drq( void )
860
861{ int unit = pcd_unit;
862 unsigned long saved_flags;
863
864 if (pcd_completion(unit,pcd_buffer,"read block")) {
865 if (pcd_retries < PCD_RETRIES) {
866 mdelay(1);
867 pcd_retries++;
868 pi_do_claimed(PI,pcd_start);
869 return;
870 }
871 spin_lock_irqsave(&io_request_lock,saved_flags);
872 pcd_busy = 0;
873 pcd_bufblk = -1;
874 end_request(0);
875 do_pcd_request(NULL);
876 spin_unlock_irqrestore(&io_request_lock,saved_flags);
877 return;
878 }
879
880 do_pcd_read();
881 spin_lock_irqsave(&io_request_lock,saved_flags);
882 do_pcd_request(NULL);
883 spin_unlock_irqrestore(&io_request_lock,saved_flags);
884}
885
886
887
888static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
889 unsigned int cmd, void *arg)
890
891{ int unit = DEVICE_NR(cdi->dev);
892
893 switch (cmd) {
894
895 case CDROMREADTOCHDR:
896
897 { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0};
898 struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
899 char buffer[32];
900 int r;
901
902 r = pcd_atapi(unit,cmd,12,buffer,"read toc header");
903
904 tochdr->cdth_trk0 = buffer[2];
905 tochdr->cdth_trk1 = buffer[3];
906
907 return r * EIO;
908 }
909
910 case CDROMREADTOCENTRY:
911
912 { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0};
913
914 struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
915 unsigned char buffer[32];
916 int r;
917
918 cmd[1] = (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
919 cmd[6] = tocentry->cdte_track;
920
921 r = pcd_atapi(unit,cmd,12,buffer,"read toc entry");
922
923 tocentry->cdte_ctrl = buffer[5] & 0xf;
924 tocentry->cdte_adr = buffer[5] >> 4;
925 tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04)?1:0;
926 if (tocentry->cdte_format == CDROM_MSF) {
927 tocentry->cdte_addr.msf.minute = buffer[9];
928 tocentry->cdte_addr.msf.second = buffer[10];
929 tocentry->cdte_addr.msf.frame = buffer[11];
930 } else
931 tocentry->cdte_addr.lba =
932 (((((buffer[8] << 8) + buffer[9]) << 8)
933 + buffer[10]) << 8) + buffer[11];
934
935 return r * EIO;
936 }
937
938 default:
939
940 return -ENOSYS;
941 }
942}
943
944static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
945
946{ char cmd[12]={GPCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0};
947 char buffer[32];
948 int k;
949 int unit = DEVICE_NR(cdi->dev);
950
951 if (pcd_atapi(unit,cmd,24,buffer,"get mcn")) return -EIO;
952
953 for (k=0;k<13;k++) mcn->medium_catalog_number[k] = buffer[k+9];
954 mcn->medium_catalog_number[13] = 0;
955
956 return 0;
957}
958
959
960
961MODULE_LICENSE("GPL");
962