#include <linux/ide.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/unaligned.h>
-#include <asm/bitops.h>
/*
* partition
*/
#define IDETAPE_DEBUG_INFO 0
#define IDETAPE_DEBUG_LOG 0
-#define IDETAPE_DEBUG_LOG_VERBOSE 0
#define IDETAPE_DEBUG_BUGS 1
/*
* driver due to an interrupt or a timer event is stored in a variable
* of type idetape_tape_t, defined below.
*/
-typedef struct {
- ide_drive_t *drive;
+typedef struct ide_tape_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+
/*
* Since a typical character device operation requires more
* than one packet command, we provide here enough memory
int debug_level;
} idetape_tape_t;
+static DECLARE_MUTEX(idetape_ref_sem);
+
+static struct class *idetape_sysfs_class;
+
+#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
+
+#define ide_tape_g(disk) \
+ container_of((disk)->private_data, struct ide_tape_obj, driver)
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+ struct ide_tape_obj *tape = NULL;
+
+ down(&idetape_ref_sem);
+ tape = ide_tape_g(disk);
+ if (tape)
+ kref_get(&tape->kref);
+ up(&idetape_ref_sem);
+ return tape;
+}
+
+static void ide_tape_release(struct kref *);
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+ down(&idetape_ref_sem);
+ kref_put(&tape->kref, ide_tape_release);
+ up(&idetape_ref_sem);
+}
+
/*
* Tape door status
*/
#define IDETAPE_ERROR_FILEMARK 102
#define IDETAPE_ERROR_EOD 103
-/*
- * idetape_chrdev_t provides the link between out character device
- * interface and our block device interface and the corresponding
- * ide_drive_t structure.
- */
-typedef struct {
- ide_drive_t *drive;
-} idetape_chrdev_t;
-
/*
* The following is used to format the general configuration word of
* the ATAPI IDENTIFY DEVICE command.
* The variables below are used for the character device interface.
* Additional state variables are defined in our ide_drive_t structure.
*/
-static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
-#if IDETAPE_DEBUG_LOG_VERBOSE
+#define ide_tape_f(file) ((file)->private_data)
-/*
- * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
- */
-
-char *idetape_sense_key_verbose(u8 idetape_sense_key)
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
{
- switch (idetape_sense_key) {
- default: {
- char buf[22];
- sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
- return(buf);
- }
-
- }
-}
-
-char *idetape_command_key_verbose(u8 idetape_command_key)
-{
- switch (idetape_command_key) {
- case IDETAPE_TEST_UNIT_READY_CMD:
- return("TEST_UNIT_READY_CMD");
- case IDETAPE_REWIND_CMD:
- return("REWIND_CMD");
- case IDETAPE_REQUEST_SENSE_CMD:
- return("REQUEST_SENSE_CMD");
- case IDETAPE_READ_CMD:
- return("READ_CMD");
- case IDETAPE_WRITE_CMD:
- return("WRITE_CMD");
- case IDETAPE_WRITE_FILEMARK_CMD:
- return("WRITE_FILEMARK_CMD");
- case IDETAPE_SPACE_CMD:
- return("SPACE_CMD");
- case IDETAPE_INQUIRY_CMD:
- return("INQUIRY_CMD");
- case IDETAPE_ERASE_CMD:
- return("ERASE_CMD");
- case IDETAPE_MODE_SENSE_CMD:
- return("MODE_SENSE_CMD");
- case IDETAPE_MODE_SELECT_CMD:
- return("MODE_SELECT_CMD");
- case IDETAPE_LOAD_UNLOAD_CMD:
- return("LOAD_UNLOAD_CMD");
- case IDETAPE_PREVENT_CMD:
- return("PREVENT_CMD");
- case IDETAPE_LOCATE_CMD:
- return("LOCATE_CMD");
- case IDETAPE_READ_POSITION_CMD:
- return("READ_POSITION_CMD");
- case IDETAPE_READ_BUFFER_CMD:
- return("READ_BUFFER_CMD");
- case IDETAPE_SET_SPEED_CMD:
- return("SET_SPEED_CMD");
- default: {
- char buf[20];
- sprintf(buf, "CMD (0x%02x)", idetape_command_key);
- return(buf);
- }
- }
+ struct ide_tape_obj *tape = NULL;
+
+ down(&idetape_ref_sem);
+ tape = idetape_devs[i];
+ if (tape)
+ kref_get(&tape->kref);
+ up(&idetape_ref_sem);
+ return tape;
}
-#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
/*
* Function declarations
"asc = %x, ascq = %x\n",
pc->c[0], result->sense_key,
result->asc, result->ascq);
-#if IDETAPE_DEBUG_LOG_VERBOSE
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: pc = %s, sense key = %x, "
- "asc = %x, ascq = %x\n",
- idetape_command_key_verbose((byte) pc->c[0]),
- result->sense_key,
- result->asc,
- result->ascq);
-#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
#endif /* IDETAPE_DEBUG_LOG */
/*
}
#endif /* IDETAPE_DEBUG_BUGS */
+ rq->rq_disk = tape->disk;
rq->buffer = NULL;
rq->special = (void *)stage->bh;
tape->active_data_request = rq;
*/
static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
{
+ struct ide_tape_obj *tape = drive->driver_data;
+
idetape_init_rq(rq, REQ_IDETAPE_PC1);
rq->buffer = (char *) pc;
+ rq->rq_disk = tape->disk;
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
#ifdef CONFIG_BLK_DEV_IDEDMA
/* Begin DMA, if necessary */
if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
- (void) (HWIF(drive)->ide_dma_begin(drive));
+ hwif->dma_start(drive);
#endif
/* Send the actual packet */
HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
"reverting to PIO\n");
(void)__ide_dma_off(drive);
}
- if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
- if (test_bit(PC_WRITING, &pc->flags))
- dma_ok = !HWIF(drive)->ide_dma_write(drive);
- else
- dma_ok = !HWIF(drive)->ide_dma_read(drive);
- }
+ if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ dma_ok = !hwif->dma_setup(drive);
if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+ if (drive->post_reset == 1) {
+ set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+ drive->post_reset = 0;
+ }
+
if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
tape->measure_insert_time = 1;
if (time_after(jiffies, tape->insert_time))
tape->dsc_polling_start = jiffies;
tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
- } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
+ } else if (time_after(jiffies, tape->dsc_timeout)) {
printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
tape->name);
if (rq->cmd[0] & REQ_IDETAPE_PC2) {
return __idetape_kmalloc_stage(tape, 0, 0);
}
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
+static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
tape->bh = bh;
}
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
+static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
}
#endif /* IDETAPE_DEBUG_BUGS */
rq->waiting = &wait;
+ rq->end_io = blk_end_sync_rq;
spin_unlock_irq(&tape->spinlock);
wait_for_completion(&wait);
/* The stage and its struct request have been deallocated */
*/
static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
{
+ struct ide_tape_obj *tape = drive->driver_data;
struct request rq;
idetape_init_rq(&rq, REQ_IDETAPE_PC1);
rq.buffer = (char *) pc;
+ rq.rq_disk = tape->disk;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
} else if (!(tape->sense_key == 2 && tape->asc == 4 &&
(tape->ascq == 1 || tape->ascq == 8)))
return -EIO;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 10);
+ msleep(100);
}
return -EIO;
}
#endif /* IDETAPE_DEBUG_BUGS */
idetape_init_rq(&rq, cmd);
+ rq.rq_disk = tape->disk;
rq.special = (void *)bh;
rq.sector = tape->first_frame_position;
rq.nr_sectors = rq.current_nr_sectors = blocks;
{
idetape_tape_t *tape = drive->driver_data;
idetape_config_t config;
+ void __user *argp = (void __user *)arg;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 4)
#endif /* IDETAPE_DEBUG_LOG */
switch (cmd) {
case 0x0340:
- if (copy_from_user ((char *) &config, (char *) arg, sizeof (idetape_config_t)))
+ if (copy_from_user(&config, argp, sizeof (idetape_config_t)))
return -EFAULT;
tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
tape->max_stages = config.nr_stages;
case 0x0350:
config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
config.nr_stages = tape->max_stages;
- if (copy_to_user((char *) arg, (char *) &config, sizeof (idetape_config_t)))
+ if (copy_to_user(argp, &config, sizeof (idetape_config_t)))
return -EFAULT;
break;
default:
return 0;
}
-/*
- * idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
-static void idetape_pre_reset (ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- if (tape != NULL)
- set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-}
-
/*
* idetape_space_over_filemarks is now a bit more complicated than just
* passing the command to the tape since we may have crossed some
* will no longer hit performance.
* This is not applicable to Onstream.
*/
-static ssize_t idetape_chrdev_read (struct file *file, char *buf,
+static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- ide_drive_t *drive = file->private_data;
- idetape_tape_t *tape = drive->driver_data;
+ struct ide_tape_obj *tape = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
ssize_t bytes_read,temp, actually_read = 0, rc;
- if (ppos != &file->f_pos) {
- /* "A request was outside the capabilities of the device." */
- return -ENXIO;
- }
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 3)
printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
return actually_read;
}
-static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
+static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- ide_drive_t *drive = file->private_data;
- idetape_tape_t *tape = drive->driver_data;
+ struct ide_tape_obj *tape = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
ssize_t retval, actually_written = 0;
- if (ppos != &file->f_pos) {
- /* "A request was outside the capabilities of the device." */
- return -ENXIO;
- }
-
/* The drive is write protected. */
if (tape->write_prot)
return -EACCES;
*/
static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- ide_drive_t *drive = file->private_data;
- idetape_tape_t *tape = drive->driver_data;
+ struct ide_tape_obj *tape = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
struct mtop mtop;
struct mtget mtget;
struct mtpos mtpos;
int block_offset = 0, position = tape->first_frame_position;
+ void __user *argp = (void __user *)arg;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 3)
}
switch (cmd) {
case MTIOCTOP:
- if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+ if (copy_from_user(&mtop, argp, sizeof (struct mtop)))
return -EFAULT;
return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
case MTIOCGET:
if (tape->drv_write_prot) {
mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
}
- if (copy_to_user((char *) arg,(char *) &mtget, sizeof(struct mtget)))
+ if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
return -EFAULT;
return 0;
case MTIOCPOS:
mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- if (copy_to_user((char *) arg,(char *) &mtpos, sizeof(struct mtpos)))
+ if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
return -EFAULT;
return 0;
default:
idetape_pc_t pc;
int retval;
+ /*
+ * We really want to do nonseekable_open(inode, filp); here, but some
+ * versions of tar incorrectly call lseek on tapes and bail out if that
+ * fails. So we disallow pread() and pwrite(), but permit lseeks.
+ */
+ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
#if IDETAPE_DEBUG_LOG
printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
#endif /* IDETAPE_DEBUG_LOG */
if (i >= MAX_HWIFS * MAX_DRIVES)
return -ENXIO;
- drive = idetape_chrdevs[i].drive;
- tape = drive->driver_data;
- filp->private_data = drive;
- if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
- return -EBUSY;
+ if (!(tape = ide_tape_chrdev_get(i)))
+ return -ENXIO;
+
+ drive = tape->drive;
+
+ filp->private_data = tape;
+
+ if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) {
+ retval = -EBUSY;
+ goto out_put_tape;
+ }
+
retval = idetape_wait_ready(drive, 60 * HZ);
if (retval) {
clear_bit(IDETAPE_BUSY, &tape->flags);
printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
- return retval;
+ goto out_put_tape;
}
idetape_read_position(drive);
if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
(filp->f_flags & O_ACCMODE) == O_RDWR) {
clear_bit(IDETAPE_BUSY, &tape->flags);
- return -EROFS;
+ retval = -EROFS;
+ goto out_put_tape;
}
}
idetape_restart_speed_control(drive);
tape->restart_speed_control_req = 0;
return 0;
+
+out_put_tape:
+ ide_tape_put(tape);
+ return retval;
}
static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
*/
static int idetape_chrdev_release (struct inode *inode, struct file *filp)
{
- ide_drive_t *drive = filp->private_data;
- idetape_tape_t *tape;
+ struct ide_tape_obj *tape = ide_tape_f(filp);
+ ide_drive_t *drive = tape->drive;
idetape_pc_t pc;
unsigned int minor = iminor(inode);
}
}
clear_bit(IDETAPE_BUSY, &tape->flags);
+ ide_tape_put(tape);
unlock_kernel();
return 0;
}
int stage_size;
struct sysinfo si;
- memset(tape, 0, sizeof (idetape_tape_t));
spin_lock_init(&tape->spinlock);
- drive->driver_data = tape;
- /* An ATAPI device ignores DRDY */
- drive->ready_stat = 0;
drive->dsc_overlap = 1;
#ifdef CONFIG_BLK_DEV_IDEPCI
if (HWIF(drive)->pci_dev != NULL) {
/* Seagate Travan drives do not support DSC overlap. */
if (strstr(drive->id->model, "Seagate STT3401"))
drive->dsc_overlap = 0;
- tape->drive = drive;
tape->minor = minor;
tape->name[0] = 'h';
tape->name[1] = 't';
idetape_add_settings(drive);
}
-static int idetape_cleanup (ide_drive_t *drive)
+static void ide_tape_remove(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- int minor = tape->minor;
- unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
- if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
- tape->first_stage != NULL || tape->merge_stage_size) {
- spin_unlock_irqrestore(&ide_lock, flags);
- return 1;
- }
- idetape_chrdevs[minor].drive = NULL;
- spin_unlock_irqrestore(&ide_lock, flags);
- DRIVER(drive)->busy = 0;
- (void) ide_unregister_subdriver(drive);
+ ide_unregister_subdriver(drive, tape->driver);
+
+ ide_unregister_region(tape->disk);
+
+ ide_tape_put(tape);
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+ struct ide_tape_obj *tape = to_ide_tape(kref);
+ ide_drive_t *drive = tape->drive;
+ struct gendisk *g = tape->disk;
+
+ BUG_ON(tape->first_stage != NULL || tape->merge_stage_size);
+
+ drive->dsc_overlap = 0;
drive->driver_data = NULL;
+ class_device_destroy(idetape_sysfs_class,
+ MKDEV(IDETAPE_MAJOR, tape->minor));
+ class_device_destroy(idetape_sysfs_class,
+ MKDEV(IDETAPE_MAJOR, tape->minor + 128));
devfs_remove("%s/mt", drive->devfs_name);
devfs_remove("%s/mtn", drive->devfs_name);
- devfs_unregister_tape(drive->disk->number);
- kfree (tape);
- drive->disk->fops = ide_fops;
- return 0;
+ devfs_unregister_tape(g->number);
+ idetape_devs[tape->minor] = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(tape);
}
#ifdef CONFIG_PROC_FS
}
static ide_proc_entry_t idetape_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
{ "name", S_IFREG|S_IRUGO, proc_idetape_read_name, NULL },
{ NULL, 0, NULL, NULL }
};
#endif
-static int idetape_attach(ide_drive_t *drive);
+static int ide_tape_probe(ide_drive_t *);
-/*
- * IDE subdriver functions, registered with ide.c
- */
static ide_driver_t idetape_driver = {
- .owner = THIS_MODULE,
- .name = "ide-tape",
+ .gen_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-tape",
+ .bus = &ide_bus_type,
+ },
+ .probe = ide_tape_probe,
+ .remove = ide_tape_remove,
.version = IDETAPE_VERSION,
.media = ide_tape,
- .busy = 1,
.supports_dsc_overlap = 1,
- .cleanup = idetape_cleanup,
.do_request = idetape_do_request,
.end_request = idetape_end_request,
- .pre_reset = idetape_pre_reset,
+ .error = __ide_error,
+ .abort = __ide_abort,
.proc = idetape_proc,
- .attach = idetape_attach,
- .drives = LIST_HEAD_INIT(idetape_driver.drives),
};
/*
static int idetape_open(struct inode *inode, struct file *filp)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_tape_obj *tape;
+ ide_drive_t *drive;
+
+ if (!(tape = ide_tape_get(disk)))
+ return -ENXIO;
+
+ drive = tape->drive;
+
drive->usage++;
+
return 0;
}
static int idetape_release(struct inode *inode, struct file *filp)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_tape_obj *tape = ide_tape_g(disk);
+ ide_drive_t *drive = tape->drive;
+
drive->usage--;
+
+ ide_tape_put(tape);
+
return 0;
}
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
- ide_drive_t *drive = bdev->bd_disk->private_data;
- int err = generic_ide_ioctl(bdev, cmd, arg);
+ struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+ ide_drive_t *drive = tape->drive;
+ int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
if (err == -EINVAL)
err = idetape_blkdev_ioctl(drive, cmd, arg);
return err;
.ioctl = idetape_ioctl,
};
-static int idetape_attach (ide_drive_t *drive)
+static int ide_tape_probe(ide_drive_t *drive)
{
idetape_tape_t *tape;
+ struct gendisk *g;
int minor;
if (!strstr("ide-tape", drive->driver_req))
printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
}
- tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+ tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL);
if (tape == NULL) {
printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
goto failed;
}
- if (ide_register_subdriver(drive, &idetape_driver)) {
- printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
- kfree(tape);
- goto failed;
- }
- for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++)
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_tape;
+
+ ide_init_disk(g, drive);
+
+ ide_register_subdriver(drive, &idetape_driver);
+
+ kref_init(&tape->kref);
+
+ tape->drive = drive;
+ tape->driver = &idetape_driver;
+ tape->disk = g;
+
+ g->private_data = &tape->driver;
+
+ drive->driver_data = tape;
+
+ down(&idetape_ref_sem);
+ for (minor = 0; idetape_devs[minor]; minor++)
;
+ idetape_devs[minor] = tape;
+ up(&idetape_ref_sem);
+
idetape_setup(drive, tape, minor);
- idetape_chrdevs[minor].drive = drive;
+
+ class_device_create(idetape_sysfs_class, NULL,
+ MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
+ class_device_create(idetape_sysfs_class, NULL,
+ MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
S_IFCHR | S_IRUGO | S_IWUGO,
S_IFCHR | S_IRUGO | S_IWUGO,
"%s/mtn", drive->devfs_name);
- drive->disk->number = devfs_register_tape(drive->devfs_name);
- drive->disk->fops = &idetape_block_ops;
+ g->number = devfs_register_tape(drive->devfs_name);
+ g->fops = &idetape_block_ops;
+ ide_register_region(g);
+
return 0;
+
+out_free_tape:
+ kfree(tape);
failed:
- return 1;
+ return -ENODEV;
}
MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
static void __exit idetape_exit (void)
{
- ide_unregister_driver(&idetape_driver);
+ driver_unregister(&idetape_driver.gen_driver);
+ class_destroy(idetape_sysfs_class);
unregister_chrdev(IDETAPE_MAJOR, "ht");
}
-/*
- * idetape_init will register the driver for each tape.
- */
-static int idetape_init (void)
+static int __init idetape_init(void)
{
+ int error = 1;
+ idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
+ if (IS_ERR(idetape_sysfs_class)) {
+ idetape_sysfs_class = NULL;
+ printk(KERN_ERR "Unable to create sysfs class for ide tapes\n");
+ error = -EBUSY;
+ goto out;
+ }
+
if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
- return -EBUSY;
+ error = -EBUSY;
+ goto out_free_class;
}
- ide_register_driver(&idetape_driver);
+
+ error = driver_register(&idetape_driver.gen_driver);
+ if (error)
+ goto out_free_driver;
+
return 0;
+
+out_free_driver:
+ driver_unregister(&idetape_driver.gen_driver);
+out_free_class:
+ class_destroy(idetape_sysfs_class);
+out:
+ return error;
}
+MODULE_ALIAS("ide:*m-tape*");
module_init(idetape_init);
module_exit(idetape_exit);
MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);