patch-2.1.15 linux/drivers/char/tpqic02.c
Next file: linux/drivers/char/tty_io.c
Previous file: linux/drivers/char/softdog.c
Back to the patch index
Back to the overall index
- Lines: 424
- Date:
Thu Dec 12 15:47:41 1996
- Orig file:
v2.1.14/linux/drivers/char/tpqic02.c
- Orig date:
Tue Oct 29 19:58:09 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
@@ -200,6 +200,15 @@
#define REALLY_SLOW_IO /* it sure is ... */
+#include <linux/config.h>
+
+#ifdef MODULE
+ #ifdef CONFIG_QIC02_DYNCONF
+ #error dynamic configuration as module not implemented!
+ #endif
+#endif
+
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
@@ -210,9 +219,9 @@
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/tpqic02.h>
-#include <linux/config.h>
#include <linux/mm.h>
-
+#include <linux/malloc.h>
+
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -333,8 +342,12 @@
* at 512 bytes, to prevent problems with 64k boundaries.
*/
+#ifdef MODULE
+static char *qic02_tape_buf = NULL;
+#else
static volatile char qic02_tape_buf[TPQBUF_SIZE+TAPE_BLKSIZE];
/* A really good compiler would be able to align this at 512 bytes... :-( */
+#endif /* MODULE */
static unsigned long buffaddr; /* aligned physical address of buffer */
@@ -1920,7 +1933,6 @@
static long qic02_tape_read(struct inode * inode, struct file * filp,
char * buf, unsigned long count)
{
- int error;
kdev_t dev = inode->i_rdev;
unsigned short flags = filp->f_flags;
unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
@@ -1946,12 +1958,6 @@
if (status_bytes_wr) /* Once written, no more reads, 'till after WFM. */
return -EACCES;
-
- /* Make sure buffer is safe to write into. */
- error = verify_area(VERIFY_WRITE, buf, count);
- if (error)
- return error;
-
/* This is rather ugly because it has to implement a finite state
* machine in order to handle the EOF situations properly.
*/
@@ -2039,7 +2045,10 @@
}
/* copy buffer to user-space in one go */
if (bytes_done>0)
- copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done);
+ if (copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr),
+ bytes_done))
+ return -EFAULT;
+
#if 1
/* Checks Ton's patch below */
if ((return_read_eof == NO) && (status_eof_detected == YES)) {
@@ -2096,7 +2105,6 @@
static long qic02_tape_write(struct inode * inode, struct file * filp,
const char * buf, unsigned long count)
{
- int error;
kdev_t dev = inode->i_rdev;
unsigned short flags = filp->f_flags;
unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
@@ -2130,11 +2138,6 @@
return -EACCES; /* don't even try when write protected */
}
- /* Make sure buffer is safe to read from. */
- error = verify_area(VERIFY_READ, buf, count);
- if (error)
- return error;
-
if (doing_read == YES)
terminate_read(0);
@@ -2167,7 +2170,9 @@
/* copy from user to DMA buffer and initiate transfer. */
if (bytes_todo>0) {
- copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo);
+ if (copy_from_user( (void *) bus_to_virt(buffaddr),
+ (const void *) buf, bytes_todo))
+ return -EFAULT;
/****************** similar problem with read() at FM could happen here at EOT.
******************/
@@ -2259,11 +2264,19 @@
kdevname(dev), flags);
}
- if (MINOR(dev)==255) /* special case for resetting */
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ if (MINOR(dev)==255) { /* special case for resetting */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
if (suser())
return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
else
return -EPERM;
+ }
if (status_dead==YES)
/* Allow `mt reset' ioctl() even when already open()ed. */
@@ -2271,6 +2284,9 @@
/* Only one at a time from here on... */
if (filp->f_count>1) { /* filp->f_count==1 for the first open() */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EBUSY;
}
@@ -2318,6 +2334,9 @@
if (s != TE_OK) {
tpqputs(TPQD_ALWAYS, "open: sense() failed");
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EIO;
}
@@ -2327,6 +2346,9 @@
*/
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
tpqputs(TPQD_ALWAYS, "No tape present.");
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EIO;
}
@@ -2355,6 +2377,9 @@
s = do_qic_cmd(QCMD_REWIND, TIM_R);
if (s != 0) {
tpqputs(TPQD_ALWAYS, "open: rewind failed");
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EIO;
}
}
@@ -2366,12 +2391,18 @@
if (status_dead==YES) {
tpqputs(TPQD_ALWAYS, "open: tape dead, attempting reset");
if (tape_reset(1)!=TE_OK) {
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -ENXIO;
} else {
status_dead = NO;
if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK) {
tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
status_dead = YES; /* try reset next time */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EIO;
}
}
@@ -2425,6 +2456,9 @@
if (s != 0) {
status_dead = YES; /* force reset */
current_tape_dev = 0; /* earlier 0xff80 */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return -EIO;
}
@@ -2441,6 +2475,9 @@
kdevname(dev));
if (status_zombie==YES) /* don't rewind in zombie mode */
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return;
/* Terminate any pending write cycle. Terminating the read-cycle
@@ -2458,7 +2495,9 @@
tpqputs(TPQD_REWIND, "release: Doing rewind...");
(void) do_qic_cmd(QCMD_REWIND, TIM_R);
}
-
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return;
} /* qic02_tape_release */
@@ -2558,7 +2597,6 @@
unsigned int iocmd, unsigned long ioarg)
{
int error;
- short i;
int dev_maj = MAJOR(inode->i_rdev);
int c;
struct mtop operation;
@@ -2588,9 +2626,9 @@
if (c == DDIOCSDBG) {
if (!suser())
return -EPERM;
- error = verify_area(VERIFY_READ, (int *) ioarg, sizeof(int));
- if (error) return error;
- c = get_user(sizeof(int), (int *) ioarg);
+ error = get_user(c, (int *) ioarg);
+ if (error)
+ return error;
if (c==0) {
QIC02_TAPE_DEBUG = 0;
return 0;
@@ -2614,15 +2652,11 @@
return -EFAULT;
}
- /* check for valid user address */
- error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(qic02_tape_dynconf));
- if (error)
- return error;
- /* copy current settings to user space */
+ /* check for valid user address and copy current settings to user space */
stp = (char *) &qic02_tape_dynconf;
argp = (char *) ioarg;
- for (i=0; i<sizeof(qic02_tape_dynconf); i++)
- put_user(*stp++, argp++);
+ if (copy_to_user(stp, argp, sizeof(qic02_tape_dynconf)))
+ return -EFAULT;
return 0;
} else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
@@ -2641,14 +2675,12 @@
return -EPERM;
if ((doing_read!=NO) || (doing_write!=NO))
return -EBUSY;
- error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(qic02_tape_dynconf));
- if (error)
- return error;
/* copy struct from user space to kernel space */
stp = (char *) &qic02_tape_dynconf;
argp = (char *) ioarg;
- copy_from_user(stp, argp, sizeof(qic02_tape_dynconf));
+ if (copy_from_user(stp, argp, sizeof(qic02_tape_dynconf)))
+ return -EFAULT;
if (status_zombie==NO)
qic02_release_resources(); /* and go zombie */
if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
@@ -2672,14 +2704,12 @@
tpqputs(TPQD_ALWAYS, "sizeof(struct mtop) does not match!");
return -EFAULT;
}
- error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(operation));
- if (error)
- return error;
/* copy mtop struct from user space to kernel space */
stp = (char *) &operation;
argp = (char *) ioarg;
- copy_from_user(stp, argp, sizeof(operation));
+ if (copy_from_user(stp, argp, sizeof(operation)))
+ return -EFAULT;
/* ---note: mt_count is signed, negative seeks must be
* --- translated to seeks in opposite direction!
@@ -2727,11 +2757,6 @@
return -EFAULT;
}
- /* check for valid user address */
- error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_status));
- if (error)
- return error;
-
/* It appears (gmt(1)) that it is normal behaviour to
* first set the status with MTNOP, and then to read
* it out with MTIOCGET
@@ -2740,8 +2765,8 @@
/* copy results to user space */
stp = (char *) &ioctl_status;
argp = (char *) ioarg;
- for (i=0; i<sizeof(ioctl_status); i++)
- put_user(*stp++, argp++);
+ if (copy_to_user(stp, argp, sizeof(ioctl_status)))
+ return -EFAULT;
return 0;
@@ -2755,11 +2780,6 @@
return -EFAULT;
}
- /* check for valid user address */
- error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_tell));
- if (error)
- return error;
-
tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
if ((doing_read==YES) || (doing_write==YES))
finish_rw(AR_QCMDV_TELL_BLK);
@@ -2773,8 +2793,8 @@
/* copy results to user space */
stp = (char *) &ioctl_tell;
argp = (char *) ioarg;
- for (i=0; i<sizeof(ioctl_tell); i++)
- put_user(*stp++, argp++);
+ if (copy_to_user(stp, argp, sizeof(ioctl_status)))
+ return -EFAULT;
return 0;
} else
@@ -2914,16 +2934,39 @@
printk(TPQIC02_NAME ": DMA buffers: %u blocks", NR_BLK_BUF);
- /* Setup the page-address for the dma transfer.
- * This assumes a one-to-one identity mapping between
- * kernel addresses and physical memory.
+ /*
+ * Setup the page-address for the dma transfer.
*/
+#ifdef MODULE
+ qic02_tape_buf = kmalloc(TPQBUF_SIZE+TAPE_BLKSIZE, GFP_DMA);
+ if (qic02_tape_buf == NULL) {
+#ifndef CONFIG_QIC02_DYNCONF
+ /*
+ * irq and dma were requested by qic_get_resources, so
+ * relase them only when _not_ using DYNCONF
+ */
+ qic02_release_resources();
+#endif
+ return -ENODEV;
+ }
+ buffaddr = align_buffer(virt_to_bus((unsigned long *)qic02_tape_buf),
+ TAPE_BLKSIZE);
+ printk(", at address 0x%lx (0x%lx)\n", buffaddr,
+ virt_to_bus((unsigned long *)qic02_tape_buf));
+#else /* no MODULE */
buffaddr = align_buffer(virt_to_bus(qic02_tape_buf), TAPE_BLKSIZE);
printk(", at address 0x%lx (0x%lx)\n", buffaddr, (unsigned long) &qic02_tape_buf);
+#endif /* MODULE */
+
#ifndef CONFIG_MAX_16M
if (buffaddr+TPQBUF_SIZE>=0x1000000) {
printk(TPQIC02_NAME ": DMA buffer *must* be in lower 16MB\n");
+#ifdef MODULE
+ qic02_release_resources();
+ kfree(qic02_tape_buf);
+#endif
+
return -ENODEV;
}
#endif
@@ -2932,8 +2975,7 @@
if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops)) {
printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
#ifndef CONFIG_QIC02_DYNCONF
- free_irq(QIC02_TAPE_IRQ, NULL);
- free_dma(QIC02_TAPE_DMA);
+ qic02_release_resources();
#endif
return -ENODEV;
}
@@ -2947,10 +2989,8 @@
if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) {
/* No drive detected, so vanish */
tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
- status_dead = YES;
- free_irq(QIC02_TAPE_IRQ, NULL);
- free_dma(QIC02_TAPE_DMA);
unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
+ qic02_release_resources();
return -ENODEV;
} else {
if (is_exception()) {
@@ -2973,3 +3013,22 @@
return 0;
} /* qic02_tape_init */
+#ifdef MODULE
+
+int init_module(void) {
+ return qic02_tape_init();
+}
+
+void cleanup_module(void) {
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
+ qic02_release_resources();
+ if (qic02_tape_buf) kfree(qic02_tape_buf);
+ sti();
+ restore_flags(flags);
+}
+
+#endif /* MODULE */
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected]