📄 pg.c
字号:
}#endif#define WR(c,r,v) pi_write_regr(PI,c,r,v)#define RR(c,r) (pi_read_regr(PI,c,r))#define DRIVE (0xa0+0x10*PG.drive)static void pg_sleep( int cs ){ current->state = TASK_INTERRUPTIBLE; schedule_timeout(cs);}static int pg_wait( int unit, int go, int stop, int tmo, char * msg ){ int j, r, e, s, p; PG.status = 0; j = 0; while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(time_before(jiffies,tmo))) { if (j++ < PG_SPIN) udelay(PG_SPIN_DEL); else pg_sleep(1); } if ((r&(STAT_ERR&stop))||time_after_eq(jiffies, tmo)) { s = RR(0,7); e = RR(0,1); p = RR(0,2); if (verbose > 1) printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n", PG.name,msg,s,e,p,time_after_eq(jiffies, tmo)?" timeout":""); if (time_after_eq(jiffies, tmo)) e |= 0x100; PG.status = (e >> 4) & 0xff; return -1; } return 0;}static int pg_command( int unit, char * cmd, int dlen, int tmo ){ int k; pi_connect(PI); WR(0,6,DRIVE); if (pg_wait(unit,STAT_BUSY|STAT_DRQ,0,tmo,"before command")) { pi_disconnect(PI); return -1; } WR(0,4,dlen % 256); WR(0,5,dlen / 256); WR(0,7,0xa0); /* ATAPI packet command */ if (pg_wait(unit,STAT_BUSY,STAT_DRQ,tmo,"command DRQ")) { pi_disconnect(PI); return -1; } if (RR(0,2) != 1) { printk("%s: command phase error\n",PG.name); pi_disconnect(PI); return -1; } pi_write_block(PI,cmd,12); if (verbose > 1) { printk("%s: Command sent, dlen=%d packet= ", PG.name,dlen); for (k=0;k<12;k++) printk("%02x ",cmd[k]&0xff); printk("\n"); } return 0;}static int pg_completion( int unit, char * buf, int tmo){ int r, d, n, p; r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR, tmo,"completion"); PG.dlen = 0; while (RR(0,7)&STAT_DRQ) { d = (RR(0,4)+256*RR(0,5)); n = ((d+3)&0xfffc); p = RR(0,2)&3; if (p == 0) pi_write_block(PI,buf,n); if (p == 2) pi_read_block(PI,buf,n); if (verbose > 1) printk("%s: %s %d bytes\n",PG.name, p?"Read":"Write",n); PG.dlen += (1-p)*d; buf += d; r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR, tmo,"completion"); } pi_disconnect(PI); return r;}static int pg_reset( int unit ){ int i, k, flg; int expect[5] = {1,1,1,0x14,0xeb}; pi_connect(PI); WR(0,6,DRIVE); WR(0,7,8); pg_sleep(20*HZ/1000); k = 0; while ((k++ < PG_RESET_TMO) && (RR(1,6)&STAT_BUSY)) pg_sleep(1); flg = 1; for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]); if (verbose) { printk("%s: Reset (%d) signature = ",PG.name,k); for (i=0;i<5;i++) printk("%3x",RR(0,i+1)); if (!flg) printk(" (incorrect)"); printk("\n"); } pi_disconnect(PI); return flg-1; }static void xs( char *buf, char *targ, int offs, int len ){ int j,k,l; j=0; l=0; for (k=0;k<len;k++) if((buf[k+offs]!=0x20)||(buf[k+offs]!=l)) l=targ[j++]=buf[k+offs]; if (l==0x20) j--; targ[j]=0;}static int pg_identify( int unit, int log ){ int s; char *ms[2] = {"master","slave"}; char mf[10], id[18]; char id_cmd[12] = { ATAPI_IDENTIFY,0,0,0,36,0,0,0,0,0,0,0}; char buf[36]; s = pg_command(unit,id_cmd,36,jiffies+PG_TMO); if (s) return -1; s = pg_completion(unit,buf,jiffies+PG_TMO); if (s) return -1; if (log) { xs(buf,mf,8,8); xs(buf,id,16,16); printk("%s: %s %s, %s\n",PG.name,mf,id,ms[PG.drive]); } return 0;}static int pg_probe( int unit )/* returns 0, with id set if drive is detected -1, if drive detection failed*/{ if (PG.drive == -1) { for (PG.drive=0;PG.drive<=1;PG.drive++) if (!pg_reset(unit)) return pg_identify(unit,1); } else { if (!pg_reset(unit)) return pg_identify(unit,1); } return -1; }static int pg_detect( void ){ int k, unit; printk("%s: %s version %s, major %d\n", name,name,PG_VERSION,major); k = 0; if (pg_drive_count == 0) { unit = 0; if (pi_init(PI,1,-1,-1,-1,-1,-1,pg_scratch, PI_PG,verbose,PG.name)) { if (!pg_probe(unit)) { PG.present = 1; k++; } else pi_release(PI); } } else for (unit=0;unit<PG_UNITS;unit++) if (DU[D_PRT]) if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI], DU[D_PRO],DU[D_DLY],pg_scratch,PI_PG,verbose, PG.name)) { if (!pg_probe(unit)) { PG.present = 1; k++; } else pi_release(PI); } if (k) return 0; printk("%s: No ATAPI device detected\n",name); return -1;}#define DEVICE_NR(dev) (minor(dev) & 0x7F)static int pg_open (struct inode *inode, struct file *file){ int unit = DEVICE_NR(inode->i_rdev); if ((unit >= PG_UNITS) || (!PG.present)) return -ENODEV; if ( test_and_set_bit(0, &PG.access) ) { return -EBUSY; } if (PG.busy) { pg_reset(unit); PG.busy = 0; } pg_identify(unit,(verbose>1)); PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL); if (PG.bufptr == NULL) { clear_bit( 0, &PG.access ) ; printk("%s: buffer allocation failed\n",PG.name); return -ENOMEM; } return 0;}static int pg_release (struct inode *inode, struct file *file){ int unit = DEVICE_NR(inode->i_rdev); if ( unit >= PG_UNITS || !test_bit(0,&PG.access) ) return -EINVAL; clear_bit( 0, &PG.access); kfree(PG.bufptr); PG.bufptr = NULL; return 0;}static ssize_t pg_write(struct file * filp, const char * buf, size_t count, loff_t *ppos){ struct inode *ino = filp->f_dentry->d_inode; int unit = DEVICE_NR(ino->i_rdev); struct pg_write_hdr hdr; int hs = sizeof(hdr); if (PG.busy) return -EBUSY; if (count < hs) return -EINVAL; copy_from_user((char *)&hdr,buf,hs); if (hdr.magic != PG_MAGIC) return -EINVAL; if (hdr.dlen > PG_MAX_DATA) return -EINVAL; if ((count - hs) > PG_MAX_DATA) return -EINVAL; if (hdr.func == PG_RESET) { if (count != hs) return -EINVAL; if (pg_reset(unit)) return -EIO; return count; } if (hdr.func != PG_COMMAND) return -EINVAL; PG.start = jiffies; PG.timeout = hdr.timeout*HZ + HZ/2 + jiffies; if (pg_command(unit,hdr.packet,hdr.dlen,jiffies+PG_TMO)) { if (PG.status & 0x10) return -ETIME; return -EIO; } PG.busy = 1; copy_from_user(PG.bufptr,buf+hs,count-hs); return count;}static ssize_t pg_read(struct file * filp, char * buf, size_t count, loff_t *ppos){ struct inode *ino = filp->f_dentry->d_inode; int unit = DEVICE_NR(ino->i_rdev); struct pg_read_hdr hdr; int hs = sizeof(hdr); int copy; if (!PG.busy) return -EINVAL; if (count < hs) return -EINVAL; PG.busy = 0; if (pg_completion(unit,PG.bufptr,PG.timeout)) if (PG.status & 0x10) return -ETIME; hdr.magic = PG_MAGIC; hdr.dlen = PG.dlen; copy = 0; if (hdr.dlen < 0) { hdr.dlen = -1 * hdr.dlen; copy = hdr.dlen; if (copy > (count - hs)) copy = count - hs; } hdr.duration = (jiffies - PG.start + HZ/2) / HZ; hdr.scsi = PG.status & 0x0f; copy_to_user(buf,(char *)&hdr,hs); if (copy > 0) copy_to_user(buf+hs,PG.bufptr,copy); return copy+hs;}/* end of pg.c */MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -