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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124#define PG_VERSION "1.02"
125#define PG_MAJOR 97
126#define PG_NAME "pg"
127#define PG_UNITS 4
128
129#ifndef PI_PG
130#define PI_PG 4
131#endif
132
133
134
135
136
137
138
139static int verbose = 0;
140static int major = PG_MAJOR;
141static char *name = PG_NAME;
142static int disable = 0;
143
144static int drive0[6] = {0,0,0,-1,-1,-1};
145static int drive1[6] = {0,0,0,-1,-1,-1};
146static int drive2[6] = {0,0,0,-1,-1,-1};
147static int drive3[6] = {0,0,0,-1,-1,-1};
148
149static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
150static int pg_drive_count;
151
152#define D_PRT 0
153#define D_PRO 1
154#define D_UNI 2
155#define D_MOD 3
156#define D_SLV 4
157#define D_DLY 5
158
159#define DU (*drives[unit])
160
161
162
163
164#include <linux/module.h>
165#include <linux/errno.h>
166#include <linux/fs.h>
167#include <linux/devfs_fs_kernel.h>
168#include <linux/kernel.h>
169#include <linux/delay.h>
170#include <linux/slab.h>
171#include <linux/mtio.h>
172#include <linux/pg.h>
173#include <linux/wait.h>
174#include <linux/smp_lock.h>
175
176#include <asm/uaccess.h>
177
178#ifndef MODULE
179
180#include "setup.h"
181
182static STT pg_stt[5] = {{"drive0",6,drive0},
183 {"drive1",6,drive1},
184 {"drive2",6,drive2},
185 {"drive3",6,drive3},
186 {"disable",1,&disable}};
187
188void pg_setup( char *str, int *ints)
189
190{ generic_setup(pg_stt,5,str);
191}
192
193#endif
194
195MODULE_PARM(verbose,"i");
196MODULE_PARM(major,"i");
197MODULE_PARM(name,"s");
198MODULE_PARM(drive0,"1-6i");
199MODULE_PARM(drive1,"1-6i");
200MODULE_PARM(drive2,"1-6i");
201MODULE_PARM(drive3,"1-6i");
202
203#include "paride.h"
204
205#define PG_SPIN_DEL 50
206#define PG_SPIN 200
207#define PG_TMO HZ
208#define PG_RESET_TMO 10*HZ
209
210#define STAT_ERR 0x01
211#define STAT_INDEX 0x02
212#define STAT_ECC 0x04
213#define STAT_DRQ 0x08
214#define STAT_SEEK 0x10
215#define STAT_WRERR 0x20
216#define STAT_READY 0x40
217#define STAT_BUSY 0x80
218
219#define ATAPI_IDENTIFY 0x12
220
221int pg_init(void);
222#ifdef MODULE
223void cleanup_module( void );
224#endif
225
226static int pg_open(struct inode *inode, struct file *file);
227static int pg_release (struct inode *inode, struct file *file);
228static ssize_t pg_read(struct file * filp, char * buf,
229 size_t count, loff_t *ppos);
230static ssize_t pg_write(struct file * filp, const char * buf,
231 size_t count, loff_t *ppos);
232static int pg_detect(void);
233
234static int pg_identify (int unit, int log);
235
236#define PG_NAMELEN 8
237
238struct pg_unit {
239 struct pi_adapter pia;
240 struct pi_adapter *pi;
241 int busy;
242 int start;
243 int dlen;
244 int timeout;
245 int status;
246 int drive;
247 int access;
248 int present;
249 char *bufptr;
250 char name[PG_NAMELEN];
251 };
252
253struct pg_unit pg[PG_UNITS];
254
255
256
257#define PG pg[unit]
258#define PI PG.pi
259
260static char pg_scratch[512];
261
262
263
264static struct file_operations pg_fops = {
265 owner: THIS_MODULE,
266 read: pg_read,
267 write: pg_write,
268 open: pg_open,
269 release: pg_release,
270};
271
272void pg_init_units( void )
273
274{ int unit, j;
275
276 pg_drive_count = 0;
277 for (unit=0;unit<PG_UNITS;unit++) {
278 PG.pi = & PG.pia;
279 PG.access = 0;
280 PG.busy = 0;
281 PG.present = 0;
282 PG.bufptr = NULL;
283 PG.drive = DU[D_SLV];
284 j = 0;
285 while ((j < PG_NAMELEN-2) && (PG.name[j]=name[j])) j++;
286 PG.name[j++] = '0' + unit;
287 PG.name[j] = 0;
288 if (DU[D_PRT]) pg_drive_count++;
289 }
290}
291
292static devfs_handle_t devfs_handle;
293
294int pg_init (void)
295
296{ int unit;
297
298 if (disable) return -1;
299
300 pg_init_units();
301
302 if (pg_detect()) return -1;
303
304 if (devfs_register_chrdev(major,name,&pg_fops)) {
305 printk("pg_init: unable to get major number %d\n",
306 major);
307 for (unit=0;unit<PG_UNITS;unit++)
308 if (PG.present) pi_release(PI);
309 return -1;
310 }
311 devfs_handle = devfs_mk_dir (NULL, "pg", NULL);
312 devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
313 major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
314 &pg_fops, NULL);
315 return 0;
316}
317
318#ifdef MODULE
319
320
321
322void cleanup_module(void);
323
324int init_module(void)
325
326{ int err;
327
328#ifdef PARIDE_JUMBO
329 { extern paride_init();
330 paride_init();
331 }
332#endif
333
334 err = pg_init();
335
336 return err;
337}
338
339void cleanup_module(void)
340
341{ int unit;
342
343 devfs_unregister (devfs_handle);
344 devfs_unregister_chrdev(major,name);
345
346 for (unit=0;unit<PG_UNITS;unit++)
347 if (PG.present) pi_release(PI);
348}
349
350#endif
351
352#define WR(c,r,v) pi_write_regr(PI,c,r,v)
353#define RR(c,r) (pi_read_regr(PI,c,r))
354
355#define DRIVE (0xa0+0x10*PG.drive)
356
357static void pg_sleep( int cs )
358
359{ current->state = TASK_INTERRUPTIBLE;
360 schedule_timeout(cs);
361}
362
363static int pg_wait( int unit, int go, int stop, int tmo, char * msg )
364
365{ int j, r, e, s, p;
366
367 PG.status = 0;
368
369 j = 0;
370 while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(time_before(jiffies,tmo))) {
371 if (j++ < PG_SPIN) udelay(PG_SPIN_DEL);
372 else pg_sleep(1);
373 }
374
375 if ((r&(STAT_ERR&stop))||time_after_eq(jiffies, tmo)) {
376 s = RR(0,7);
377 e = RR(0,1);
378 p = RR(0,2);
379 if (verbose > 1)
380 printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
381 PG.name,msg,s,e,p,time_after_eq(jiffies, tmo)?" timeout":"");
382
383
384 if (time_after_eq(jiffies, tmo)) e |= 0x100;
385 PG.status = (e >> 4) & 0xff;
386 return -1;
387 }
388 return 0;
389}
390
391static int pg_command( int unit, char * cmd, int dlen, int tmo )
392
393{ int k;
394
395 pi_connect(PI);
396
397 WR(0,6,DRIVE);
398
399 if (pg_wait(unit,STAT_BUSY|STAT_DRQ,0,tmo,"before command")) {
400 pi_disconnect(PI);
401 return -1;
402 }
403
404 WR(0,4,dlen % 256);
405 WR(0,5,dlen / 256);
406 WR(0,7,0xa0);
407
408 if (pg_wait(unit,STAT_BUSY,STAT_DRQ,tmo,"command DRQ")) {
409 pi_disconnect(PI);
410 return -1;
411 }
412
413 if (RR(0,2) != 1) {
414 printk("%s: command phase error\n",PG.name);
415 pi_disconnect(PI);
416 return -1;
417 }
418
419 pi_write_block(PI,cmd,12);
420
421 if (verbose > 1) {
422 printk("%s: Command sent, dlen=%d packet= ", PG.name,dlen);
423 for (k=0;k<12;k++) printk("%02x ",cmd[k]&0xff);
424 printk("\n");
425 }
426 return 0;
427}
428
429static int pg_completion( int unit, char * buf, int tmo)
430
431{ int r, d, n, p;
432
433 r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
434 tmo,"completion");
435
436 PG.dlen = 0;
437
438 while (RR(0,7)&STAT_DRQ) {
439 d = (RR(0,4)+256*RR(0,5));
440 n = ((d+3)&0xfffc);
441 p = RR(0,2)&3;
442 if (p == 0) pi_write_block(PI,buf,n);
443 if (p == 2) pi_read_block(PI,buf,n);
444 if (verbose > 1) printk("%s: %s %d bytes\n",PG.name,
445 p?"Read":"Write",n);
446 PG.dlen += (1-p)*d;
447 buf += d;
448 r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
449 tmo,"completion");
450 }
451
452 pi_disconnect(PI);
453
454 return r;
455}
456
457static int pg_reset( int unit )
458
459{ int i, k, flg;
460 int expect[5] = {1,1,1,0x14,0xeb};
461
462 pi_connect(PI);
463 WR(0,6,DRIVE);
464 WR(0,7,8);
465
466 pg_sleep(20*HZ/1000);
467
468 k = 0;
469 while ((k++ < PG_RESET_TMO) && (RR(1,6)&STAT_BUSY))
470 pg_sleep(1);
471
472 flg = 1;
473 for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
474
475 if (verbose) {
476 printk("%s: Reset (%d) signature = ",PG.name,k);
477 for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
478 if (!flg) printk(" (incorrect)");
479 printk("\n");
480 }
481
482 pi_disconnect(PI);
483 return flg-1;
484}
485
486static void xs( char *buf, char *targ, int offs, int len )
487
488{ int j,k,l;
489
490 j=0; l=0;
491 for (k=0;k<len;k++)
492 if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
493 l=targ[j++]=buf[k+offs];
494 if (l==0x20) j--;
495 targ[j]=0;
496}
497
498static int pg_identify( int unit, int log )
499
500{ int s;
501 char *ms[2] = {"master","slave"};
502 char mf[10], id[18];
503 char id_cmd[12] = { ATAPI_IDENTIFY,0,0,0,36,0,0,0,0,0,0,0};
504 char buf[36];
505
506 s = pg_command(unit,id_cmd,36,jiffies+PG_TMO);
507 if (s) return -1;
508 s = pg_completion(unit,buf,jiffies+PG_TMO);
509 if (s) return -1;
510
511 if (log) {
512 xs(buf,mf,8,8);
513 xs(buf,id,16,16);
514 printk("%s: %s %s, %s\n",PG.name,mf,id,ms[PG.drive]);
515 }
516
517 return 0;
518}
519
520static int pg_probe( int unit )
521
522
523
524
525
526{ if (PG.drive == -1) {
527 for (PG.drive=0;PG.drive<=1;PG.drive++)
528 if (!pg_reset(unit)) return pg_identify(unit,1);
529 } else {
530 if (!pg_reset(unit)) return pg_identify(unit,1);
531 }
532 return -1;
533}
534
535static int pg_detect( void )
536
537{ int k, unit;
538
539 printk("%s: %s version %s, major %d\n",
540 name,name,PG_VERSION,major);
541
542 k = 0;
543 if (pg_drive_count == 0) {
544 unit = 0;
545 if (pi_init(PI,1,-1,-1,-1,-1,-1,pg_scratch,
546 PI_PG,verbose,PG.name)) {
547 if (!pg_probe(unit)) {
548 PG.present = 1;
549 k++;
550 } else pi_release(PI);
551 }
552
553 } else for (unit=0;unit<PG_UNITS;unit++) if (DU[D_PRT])
554 if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
555 DU[D_PRO],DU[D_DLY],pg_scratch,PI_PG,verbose,
556 PG.name)) {
557 if (!pg_probe(unit)) {
558 PG.present = 1;
559 k++;
560 } else pi_release(PI);
561 }
562
563 if (k) return 0;
564
565 printk("%s: No ATAPI device detected\n",name);
566 return -1;
567}
568
569#define DEVICE_NR(dev) (MINOR(dev) % 128)
570
571static int pg_open (struct inode *inode, struct file *file)
572
573{ int unit = DEVICE_NR(inode->i_rdev);
574
575 if ((unit >= PG_UNITS) || (!PG.present)) return -ENODEV;
576
577 PG.access++;
578
579 if (PG.access > 1) {
580 PG.access--;
581 return -EBUSY;
582 }
583
584 if (PG.busy) {
585 pg_reset(unit);
586 PG.busy = 0;
587 }
588
589 pg_identify(unit,(verbose>1));
590
591
592 PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL);
593 if (PG.bufptr == NULL) {
594 PG.access--;
595 printk("%s: buffer allocation failed\n",PG.name);
596 return -ENOMEM;
597 }
598
599 return 0;
600}
601
602static int pg_release (struct inode *inode, struct file *file)
603{
604 int unit = DEVICE_NR(inode->i_rdev);
605
606 if ((unit >= PG_UNITS) || (PG.access <= 0))
607 return -EINVAL;
608
609 lock_kernel();
610 PG.access--;
611
612 kfree(PG.bufptr);
613 PG.bufptr = NULL;
614 unlock_kernel();
615
616 return 0;
617
618}
619
620static ssize_t pg_write(struct file * filp, const char * buf,
621 size_t count, loff_t *ppos)
622
623{ struct inode *ino = filp->f_dentry->d_inode;
624 int unit = DEVICE_NR(ino->i_rdev);
625 struct pg_write_hdr hdr;
626 int hs = sizeof(hdr);
627
628 if (PG.busy) return -EBUSY;
629 if (count < hs) return -EINVAL;
630
631 if (copy_from_user((char *)&hdr, buf, hs))
632 return -EFAULT;
633
634 if (hdr.magic != PG_MAGIC) return -EINVAL;
635 if (hdr.dlen > PG_MAX_DATA) return -EINVAL;
636 if ((count - hs) > PG_MAX_DATA) return -EINVAL;
637
638 if (hdr.func == PG_RESET) {
639 if (count != hs) return -EINVAL;
640 if (pg_reset(unit)) return -EIO;
641 return count;
642 }
643
644 if (hdr.func != PG_COMMAND) return -EINVAL;
645
646 PG.start = jiffies;
647 PG.timeout = hdr.timeout*HZ + HZ/2 + jiffies;
648
649 if (pg_command(unit,hdr.packet,hdr.dlen,jiffies+PG_TMO)) {
650 if (PG.status & 0x10) return -ETIME;
651 return -EIO;
652 }
653
654 PG.busy = 1;
655
656 if (copy_from_user(PG.bufptr, buf + hs, count - hs))
657 return -EFAULT;
658 return count;
659}
660
661static ssize_t pg_read(struct file * filp, char * buf,
662 size_t count, loff_t *ppos)
663
664{ struct inode *ino = filp->f_dentry->d_inode;
665 int unit = DEVICE_NR(ino->i_rdev);
666 struct pg_read_hdr hdr;
667 int hs = sizeof(hdr);
668 int copy;
669
670 if (!PG.busy) return -EINVAL;
671 if (count < hs) return -EINVAL;
672
673 PG.busy = 0;
674
675 if (pg_completion(unit,PG.bufptr,PG.timeout))
676 if (PG.status & 0x10) return -ETIME;
677
678 hdr.magic = PG_MAGIC;
679 hdr.dlen = PG.dlen;
680 copy = 0;
681
682 if (hdr.dlen < 0) {
683 hdr.dlen = -1 * hdr.dlen;
684 copy = hdr.dlen;
685 if (copy > (count - hs)) copy = count - hs;
686 }
687
688 hdr.duration = (jiffies - PG.start + HZ/2) / HZ;
689 hdr.scsi = PG.status & 0x0f;
690
691 if (copy_to_user(buf, (char *)&hdr, hs))
692 return -EFAULT;
693 if (copy > 0)
694 if (copy_to_user(buf+hs,PG.bufptr,copy))
695 return -EFAULT;
696 return copy+hs;
697}
698
699
700
701MODULE_LICENSE("GPL");
702