patch-2.1.23 linux/drivers/ap1000/ap.c
Next file: linux/drivers/ap1000/apfddi-reg.h
Previous file: linux/drivers/ap1000/am79c864.h
Back to the patch index
Back to the overall index
- Lines: 319
- Date:
Sun Jan 26 12:07:10 1997
- Orig file:
v2.1.22/linux/drivers/ap1000/ap.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v2.1.22/linux/drivers/ap1000/ap.c linux/drivers/ap1000/ap.c
@@ -0,0 +1,318 @@
+ /*
+ * Copyright 1996 The Australian National University.
+ * Copyright 1996 Fujitsu Laboratories Limited
+ *
+ * This software may be distributed under the terms of the Gnu
+ * Public License version 2 or later
+ */
+/*
+ * ap.c - Single AP1000 block driver.
+ *
+ * (C) dwalsh, Pious project, DCS, ANU 1996
+ *
+ * This block driver is designed to simply to perform
+ * io operations to the hosts file system.
+ *
+ * Heavily modified by tridge
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/ap1000/apservice.h>
+
+#define AP_DEBUG 0
+
+#define MAJOR_NR APBLOCK_MAJOR
+#define AP_DRIVER 1
+#include <linux/blk.h>
+
+#define NUM_APDEVS 8
+#define MAX_REQUESTS 1
+
+static struct wait_queue * busy_wait = NULL;
+
+static int ap_blocksizes[NUM_APDEVS];
+static int ap_length[NUM_APDEVS];
+static int ap_fds[NUM_APDEVS];
+
+#define SECTOR_BLOCK_SHIFT 9
+#define AP_BLOCK_SHIFT 12 /* 4k blocks */
+#define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
+
+static volatile int request_count = 0;
+
+#ifdef MODULE
+static void ap_release(struct inode * inode, struct file * filp)
+{
+ MOD_DEC_USE_COUNT;
+}
+#endif
+
+static void ap_request(void)
+{
+ struct cap_request creq;
+ unsigned int minor;
+ int offset, len;
+ struct request *req;
+
+ if (request_count >= MAX_REQUESTS) return;
+
+repeat:
+
+ if (!CURRENT) {
+ return;
+ }
+
+ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
+ panic(DEVICE_NAME ": request list destroyed");
+ }
+ if (CURRENT->bh) {
+ if (!buffer_locked(CURRENT->bh)) {
+ panic(DEVICE_NAME ": block not locked");
+ }
+ }
+
+ req = CURRENT;
+
+ minor = MINOR(req->rq_dev);
+
+ if (minor >= NUM_APDEVS) {
+ printk("apblock: request for invalid minor %d\n",minor);
+ end_request(0);
+ goto repeat;
+ }
+
+ offset = req->sector;
+ len = req->current_nr_sectors;
+
+ if ((offset + len) > ap_length[minor]) {
+ printk("apblock: request for invalid sectors %d -> %d\n",
+ offset,offset+len);
+ end_request(0);
+ goto repeat;
+ }
+
+ if (ap_fds[minor] == -1) {
+ printk("apblock: minor %d not open\n",minor);
+ end_request(0);
+ goto repeat;
+ }
+
+ /* convert to our units */
+ offset <<= SECTOR_BLOCK_SHIFT;
+ len <<= SECTOR_BLOCK_SHIFT;
+
+ /* setup a request for the host */
+ creq.cid = mpp_cid();
+ creq.size = sizeof(creq);
+ creq.header = 0;
+ creq.data[0] = (int)(req);
+ creq.data[1] = ap_fds[minor];
+ creq.data[2] = offset;
+ creq.data[3] = len;
+
+ switch (req->cmd) {
+ case READ:
+#if AP_DEBUG
+ printk("apblock: read req=0x%x len=%d offset=%d\n",
+ req,len,offset);
+#endif
+ creq.type = REQ_BREAD;
+ if (bif_queue(&creq,0,0)) {
+ return;
+ }
+ break;
+
+ case WRITE:
+#if AP_DEBUG
+ printk("apblock: write req=0x%x len=%d offset=%d\n",
+ req,len,offset);
+#endif
+ creq.type = REQ_BWRITE;
+ creq.size += len;
+ if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) {
+ return;
+ }
+ break;
+
+ default:
+ printk("apblock: unknown ap op %d\n",req->cmd);
+ end_request(0);
+ return;
+ }
+
+ if (++request_count < MAX_REQUESTS)
+ goto repeat;
+}
+
+/* this is called by ap1000/bif.c when a read/write has completed */
+void ap_complete(struct cap_request *creq)
+{
+#if AP_DEBUG
+ struct request *req = (struct request *)(creq->data[0]);
+
+ printk("request 0x%x complete\n",req);
+#endif
+ end_request(1);
+ request_count--;
+ ap_request();
+}
+
+
+/* this is called by ap1000/bif.c to find a buffer to put a BREAD into
+ using DMA */
+char *ap_buffer(struct cap_request *creq)
+{
+ struct request *req = (struct request *)(creq->data[0]);
+
+ return(req->buffer);
+}
+
+
+static int ap_open(struct inode * inode, struct file * filp)
+{
+ struct cap_request creq;
+ int minor;
+ minor = DEVICE_NR(inode->i_rdev);
+
+#if AP_DEBUG
+ printk("ap_open: minor=%x\n", minor);
+#endif
+
+ if (minor >= NUM_APDEVS)
+ return -ENODEV;
+
+ /* if its already open then don't do anything */
+ if (ap_fds[minor] != -1)
+ return 0;
+
+ /* send the open request to the front end */
+ creq.cid = mpp_cid();
+ creq.type = REQ_BOPEN;
+ creq.header = 0;
+ creq.size = sizeof(creq);
+ creq.data[0] = minor;
+
+ bif_queue(&creq,0,0);
+
+ /* wait for the reply */
+ while (ap_fds[minor] == -1)
+ sleep_on(&busy_wait);
+
+ return 0;
+}
+
+
+static int ap_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ if (!inode || !inode->i_rdev)
+ return -EINVAL;
+
+ switch (cmd) {
+ case BLKGETSIZE: /* Return device size */
+ if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg))
+ return -EFAULT;
+ return 0;
+
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+
+/* this is called by ap1000/bif.c when a open reply comes in */
+void ap_open_reply(struct cap_request *creq)
+{
+ int minor = creq->data[0];
+
+ ap_fds[minor] = creq->data[1];
+ ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT;
+
+#if AP_DEBUG
+ printk("ap opened minor %d length=%d fd=%d\n",
+ minor,ap_length[minor],ap_fds[minor]);
+#endif
+
+ wake_up(&busy_wait);
+}
+
+static struct file_operations ap_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* poll */
+ ap_ioctl, /* ioctl */
+ NULL, /* mmap */
+ ap_open, /* open */
+#ifndef MODULE
+ NULL, /* no special release code... */
+#else
+ ap_release, /* module needs to decrement use count */
+#endif
+ block_fsync, /* fsync */
+};
+
+
+int ap_init(void)
+{
+ int i;
+ static int done = 0;
+
+ if (done) return(1);
+
+ if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) {
+ printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR);
+ return -1;
+ }
+ printk("ap_init: register dev %d\n", MAJOR_NR);
+ blk_dev[MAJOR_NR].request_fn = &ap_request;
+
+ for (i=0;i<NUM_APDEVS;i++) {
+ ap_blocksizes[i] = AP_BLOCK_SIZE;
+ ap_length[i] = 0;
+ ap_fds[i] = -1;
+ }
+
+ blksize_size[MAJOR_NR] = ap_blocksizes;
+
+ read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
+
+ return(0);
+}
+
+/* loadable module support */
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ int error = ap_init();
+ if (!error)
+ printk(KERN_INFO "APBLOCK: Loaded as module.\n");
+ return error;
+}
+
+/* Before freeing the module, invalidate all of the protected buffers! */
+void cleanup_module(void)
+{
+ int i;
+
+ for (i = 0 ; i < NUM_APDEVS; i++)
+ invalidate_buffers(MKDEV(MAJOR_NR, i));
+
+ unregister_blkdev( MAJOR_NR, "apblock" );
+ blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov