📄 pt.c
字号:
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 xn(char *buf, int offs, int size){ int v, k; v = 0; for (k = 0; k < size; k++) v = v * 256 + (buf[k + offs] & 0xff); return v;}static int pt_identify(struct pt_unit *tape){ int dt, 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 ms_cmd[12] = { ATAPI_MODE_SENSE, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; char ls_cmd[12] = { ATAPI_LOG_SENSE, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 }; char buf[36]; s = pt_atapi(tape, id_cmd, 36, buf, "identify"); if (s) return -1; dt = buf[0] & 0x1f; if (dt != 1) { if (verbose) printk("%s: Drive %d, unsupported type %d\n", tape->name, tape->drive, dt); return -1; } xs(buf, mf, 8, 8); xs(buf, id, 16, 16); tape->flags = 0; tape->capacity = 0; tape->bs = 0; if (!pt_ready_wait(tape, PT_READY_TMO)) tape->flags |= PT_MEDIA; if (!pt_atapi(tape, ms_cmd, 36, buf, "mode sense")) { if (!(buf[2] & 0x80)) tape->flags |= PT_WRITE_OK; tape->bs = xn(buf, 10, 2); } if (!pt_atapi(tape, ls_cmd, 36, buf, "log sense")) tape->capacity = xn(buf, 24, 4); printk("%s: %s %s, %s", tape->name, mf, id, ms[tape->drive]); if (!(tape->flags & PT_MEDIA)) printk(", no media\n"); else { if (!(tape->flags & PT_WRITE_OK)) printk(", RO"); printk(", blocksize %d, %d MB\n", tape->bs, tape->capacity / 1024); } return 0;}/* * returns 0, with id set if drive is detected * -1, if drive detection failed */static int pt_probe(struct pt_unit *tape){ if (tape->drive == -1) { for (tape->drive = 0; tape->drive <= 1; tape->drive++) if (!pt_reset(tape)) return pt_identify(tape); } else { if (!pt_reset(tape)) return pt_identify(tape); } return -1;}static int pt_detect(void){ struct pt_unit *tape; int specified = 0, found = 0; int unit; printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major); specified = 0; for (unit = 0; unit < PT_UNITS; unit++) { struct pt_unit *tape = &pt[unit]; tape->pi = &tape->pia; atomic_set(&tape->available, 1); tape->flags = 0; tape->last_sense = 0; tape->present = 0; tape->bufptr = NULL; tape->drive = DU[D_SLV]; snprintf(tape->name, PT_NAMELEN, "%s%d", name, unit); if (!DU[D_PRT]) continue; specified++; if (pi_init(tape->pi, 0, DU[D_PRT], DU[D_MOD], DU[D_UNI], DU[D_PRO], DU[D_DLY], pt_scratch, PI_PT, verbose, tape->name)) { if (!pt_probe(tape)) { tape->present = 1; found++; } else pi_release(tape->pi); } } if (specified == 0) { tape = pt; if (pi_init(tape->pi, 1, -1, -1, -1, -1, -1, pt_scratch, PI_PT, verbose, tape->name)) { if (!pt_probe(tape)) { tape->present = 1; found++; } else pi_release(tape->pi); } } if (found) return 0; printk("%s: No ATAPI tape drive detected\n", name); return -1;}static int pt_open(struct inode *inode, struct file *file){ int unit = iminor(inode) & 0x7F; struct pt_unit *tape = pt + unit; int err; if (unit >= PT_UNITS || (!tape->present)) return -ENODEV; err = -EBUSY; if (!atomic_dec_and_test(&tape->available)) goto out; pt_identify(tape); err = -ENODEV; if (!tape->flags & PT_MEDIA) goto out; err = -EROFS; if ((!tape->flags & PT_WRITE_OK) && (file->f_mode & 2)) goto out; if (!(iminor(inode) & 128)) tape->flags |= PT_REWIND; err = -ENOMEM; tape->bufptr = kmalloc(PT_BUFSIZE, GFP_KERNEL); if (tape->bufptr == NULL) { printk("%s: buffer allocation failed\n", tape->name); goto out; } file->private_data = tape; return 0;out: atomic_inc(&tape->available); return err;}static int pt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct pt_unit *tape = file->private_data; struct mtop __user *p = (void __user *)arg; struct mtop mtop; switch (cmd) { case MTIOCTOP: if (copy_from_user(&mtop, p, sizeof(struct mtop))) return -EFAULT; switch (mtop.mt_op) { case MTREW: pt_rewind(tape); return 0; case MTWEOF: pt_write_fm(tape); return 0; default: printk("%s: Unimplemented mt_op %d\n", tape->name, mtop.mt_op); return -EINVAL; } default: printk("%s: Unimplemented ioctl 0x%x\n", tape->name, cmd); return -EINVAL; }}static intpt_release(struct inode *inode, struct file *file){ struct pt_unit *tape = file->private_data; if (atomic_read(&tape->available) > 1) return -EINVAL; if (tape->flags & PT_WRITING) pt_write_fm(tape); if (tape->flags & PT_REWIND) pt_rewind(tape); kfree(tape->bufptr); tape->bufptr = NULL; atomic_inc(&tape->available); return 0;}static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos){ struct pt_unit *tape = filp->private_data; struct pi_adapter *pi = tape->pi; char rd_cmd[12] = { ATAPI_READ_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int k, n, r, p, s, t, b; if (!(tape->flags & (PT_READING | PT_WRITING))) { tape->flags |= PT_READING; if (pt_atapi(tape, rd_cmd, 0, NULL, "start read-ahead")) return -EIO; } else if (tape->flags & PT_WRITING) return -EIO; if (tape->flags & PT_EOF) return 0; t = 0; while (count > 0) { if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "read")) return -EIO; n = count; if (n > 32768) n = 32768; /* max per command */ b = (n - 1 + tape->bs) / tape->bs; n = b * tape->bs; /* rounded up to even block */ rd_cmd[4] = b; r = pt_command(tape, rd_cmd, n, "read"); mdelay(1); if (r) { pt_req_sense(tape, 0); return -EIO; } while (1) { r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_ERR | STAT_READY, DBMSG("read DRQ"), ""); if (r & STAT_SENSE) { pi_disconnect(pi); pt_req_sense(tape, 0); return -EIO; } if (r) tape->flags |= PT_EOF; s = read_reg(pi, 7); if (!(s & STAT_DRQ)) break; n = (read_reg(pi, 4) + 256 * read_reg(pi, 5)); p = (read_reg(pi, 2) & 3); if (p != 2) { pi_disconnect(pi); printk("%s: Phase error on read: %d\n", tape->name, p); return -EIO; } while (n > 0) { k = n; if (k > PT_BUFSIZE) k = PT_BUFSIZE; pi_read_block(pi, tape->bufptr, k); n -= k; b = k; if (b > count) b = count; if (copy_to_user(buf + t, tape->bufptr, b)) { pi_disconnect(pi); return -EFAULT; } t += b; count -= b; } } pi_disconnect(pi); if (tape->flags & PT_EOF) break; } return t;}static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos){ struct pt_unit *tape = filp->private_data; struct pi_adapter *pi = tape->pi; char wr_cmd[12] = { ATAPI_WRITE_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int k, n, r, p, s, t, b; if (!(tape->flags & PT_WRITE_OK)) return -EROFS; if (!(tape->flags & (PT_READING | PT_WRITING))) { tape->flags |= PT_WRITING; if (pt_atapi (tape, wr_cmd, 0, NULL, "start buffer-available mode")) return -EIO; } else if (tape->flags & PT_READING) return -EIO; if (tape->flags & PT_EOF) return -ENOSPC; t = 0; while (count > 0) { if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "write")) return -EIO; n = count; if (n > 32768) n = 32768; /* max per command */ b = (n - 1 + tape->bs) / tape->bs; n = b * tape->bs; /* rounded up to even block */ wr_cmd[4] = b; r = pt_command(tape, wr_cmd, n, "write"); mdelay(1); if (r) { /* error delivering command only */ pt_req_sense(tape, 0); return -EIO; } while (1) { r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_ERR | STAT_READY, DBMSG("write DRQ"), NULL); if (r & STAT_SENSE) { pi_disconnect(pi); pt_req_sense(tape, 0); return -EIO; } if (r) tape->flags |= PT_EOF; s = read_reg(pi, 7); if (!(s & STAT_DRQ)) break; n = (read_reg(pi, 4) + 256 * read_reg(pi, 5)); p = (read_reg(pi, 2) & 3); if (p != 0) { pi_disconnect(pi); printk("%s: Phase error on write: %d \n", tape->name, p); return -EIO; } while (n > 0) { k = n; if (k > PT_BUFSIZE) k = PT_BUFSIZE; b = k; if (b > count) b = count; if (copy_from_user(tape->bufptr, buf + t, b)) { pi_disconnect(pi); return -EFAULT; } pi_write_block(pi, tape->bufptr, k); t += b; count -= b; n -= k; } } pi_disconnect(pi); if (tape->flags & PT_EOF) break; } return t;}static int __init pt_init(void){ int unit, err = 0; if (disable) { err = -1; goto out; } if (pt_detect()) { err = -1; goto out; } if (register_chrdev(major, name, &pt_fops)) { printk("pt_init: unable to get major number %d\n", major); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) pi_release(pt[unit].pi); err = -1; goto out; } pt_class = class_simple_create(THIS_MODULE, "pt"); if (IS_ERR(pt_class)) { err = PTR_ERR(pt_class); goto out_chrdev; } devfs_mk_dir("pt"); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { class_simple_device_add(pt_class, MKDEV(major, unit), NULL, "pt%d", unit); err = devfs_mk_cdev(MKDEV(major, unit), S_IFCHR | S_IRUSR | S_IWUSR, "pt/%d", unit); if (err) { class_simple_device_remove(MKDEV(major, unit)); goto out_class; } class_simple_device_add(pt_class, MKDEV(major, unit + 128), NULL, "pt%dn", unit); err = devfs_mk_cdev(MKDEV(major, unit + 128), S_IFCHR | S_IRUSR | S_IWUSR, "pt/%dn", unit); if (err) { class_simple_device_remove(MKDEV(major, unit + 128)); goto out_class; } } goto out;out_class: class_simple_destroy(pt_class);out_chrdev: unregister_chrdev(major, "pt");out: return err;}static void __exit pt_exit(void){ int unit; for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { class_simple_device_remove(MKDEV(major, unit)); devfs_remove("pt/%d", unit); class_simple_device_remove(MKDEV(major, unit + 128)); devfs_remove("pt/%dn", unit); } class_simple_destroy(pt_class); devfs_remove("pt"); unregister_chrdev(major, name); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) pi_release(pt[unit].pi);}MODULE_LICENSE("GPL");module_init(pt_init)module_exit(pt_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -