Import 2.1.118
[davej-history.git] / drivers / ap1000 / ap.c
blobce50c5edb31957d6fa3c8bd9048f4e9cf7633154
1 /*
2 * Copyright 1996 The Australian National University.
3 * Copyright 1996 Fujitsu Laboratories Limited
4 *
5 * This software may be distributed under the terms of the Gnu
6 * Public License version 2 or later
7 */
8 /*
9 * ap.c - Single AP1000 block driver.
11 * (C) dwalsh, Pious project, DCS, ANU 1996
13 * This block driver is designed to simply to perform
14 * io operations to the hosts file system.
16 * Heavily modified by tridge
20 #include <linux/errno.h>
21 #include <linux/types.h>
22 #include <linux/fs.h>
23 #include <linux/ext2_fs.h>
24 #include <linux/kernel.h>
25 #include <linux/major.h>
26 #include <linux/module.h>
27 #include <asm/uaccess.h>
28 #include <asm/ap1000/apservice.h>
30 #define AP_DEBUG 0
32 #define MAJOR_NR APBLOCK_MAJOR
33 #define AP_DRIVER 1
34 #include <linux/blk.h>
36 #define NUM_APDEVS 8
37 #define MAX_REQUESTS 1
39 static struct wait_queue * busy_wait = NULL;
41 static int ap_blocksizes[NUM_APDEVS];
42 static int ap_length[NUM_APDEVS];
43 static int ap_fds[NUM_APDEVS];
45 #define SECTOR_BLOCK_SHIFT 9
46 #define AP_BLOCK_SHIFT 12 /* 4k blocks */
47 #define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
49 static volatile int request_count = 0;
51 static void ap_release(struct inode * inode, struct file * filp)
53 MOD_DEC_USE_COUNT;
56 static void ap_request(void)
58 struct cap_request creq;
59 unsigned int minor;
60 int offset, len;
61 struct request *req;
63 if (request_count >= MAX_REQUESTS) return;
65 repeat:
67 if (!CURRENT) {
68 return;
71 if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
72 panic(DEVICE_NAME ": request list destroyed");
74 if (CURRENT->bh) {
75 if (!buffer_locked(CURRENT->bh)) {
76 panic(DEVICE_NAME ": block not locked");
80 req = CURRENT;
82 minor = MINOR(req->rq_dev);
84 if (minor >= NUM_APDEVS) {
85 printk("apblock: request for invalid minor %d\n",minor);
86 end_request(0);
87 goto repeat;
90 offset = req->sector;
91 len = req->current_nr_sectors;
93 if ((offset + len) > ap_length[minor]) {
94 printk("apblock: request for invalid sectors %d -> %d\n",
95 offset,offset+len);
96 end_request(0);
97 goto repeat;
100 if (ap_fds[minor] == -1) {
101 printk("apblock: minor %d not open\n",minor);
102 end_request(0);
103 goto repeat;
106 /* convert to our units */
107 offset <<= SECTOR_BLOCK_SHIFT;
108 len <<= SECTOR_BLOCK_SHIFT;
110 /* setup a request for the host */
111 creq.cid = mpp_cid();
112 creq.size = sizeof(creq);
113 creq.header = 0;
114 creq.data[0] = (int)(req);
115 creq.data[1] = ap_fds[minor];
116 creq.data[2] = offset;
117 creq.data[3] = len;
119 switch (req->cmd) {
120 case READ:
121 #if AP_DEBUG
122 printk("apblock: read req=0x%x len=%d offset=%d\n",
123 req,len,offset);
124 #endif
125 creq.type = REQ_BREAD;
126 if (bif_queue(&creq,0,0)) {
127 return;
129 break;
131 case WRITE:
132 #if AP_DEBUG
133 printk("apblock: write req=0x%x len=%d offset=%d\n",
134 req,len,offset);
135 #endif
136 creq.type = REQ_BWRITE;
137 creq.size += len;
138 if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) {
139 return;
141 break;
143 default:
144 printk("apblock: unknown ap op %d\n",req->cmd);
145 end_request(0);
146 return;
149 if (++request_count < MAX_REQUESTS)
150 goto repeat;
153 /* this is called by ap1000/bif.c when a read/write has completed */
154 void ap_complete(struct cap_request *creq)
156 #if AP_DEBUG
157 struct request *req = (struct request *)(creq->data[0]);
159 printk("request 0x%x complete\n",req);
160 #endif
161 end_request(1);
162 request_count--;
163 ap_request();
167 /* this is called by ap1000/bif.c to find a buffer to put a BREAD into
168 using DMA */
169 char *ap_buffer(struct cap_request *creq)
171 struct request *req = (struct request *)(creq->data[0]);
173 return(req->buffer);
177 static int ap_open(struct inode * inode, struct file * filp)
179 struct cap_request creq;
180 int minor;
181 minor = DEVICE_NR(inode->i_rdev);
183 #if AP_DEBUG
184 printk("ap_open: minor=%x\n", minor);
185 #endif
187 if (minor >= NUM_APDEVS)
188 return -ENODEV;
190 /* if its already open then don't do anything */
191 if (ap_fds[minor] != -1)
192 return 0;
194 /* send the open request to the front end */
195 creq.cid = mpp_cid();
196 creq.type = REQ_BOPEN;
197 creq.header = 0;
198 creq.size = sizeof(creq);
199 creq.data[0] = minor;
201 bif_queue(&creq,0,0);
203 /* wait for the reply */
204 while (ap_fds[minor] == -1)
205 sleep_on(&busy_wait);
207 return 0;
211 static int ap_ioctl(struct inode *inode, struct file *file,
212 unsigned int cmd, unsigned long arg)
214 if (!inode || !inode->i_rdev)
215 return -EINVAL;
217 switch (cmd) {
218 case BLKGETSIZE: /* Return device size */
219 if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg))
220 return -EFAULT;
221 return 0;
223 default:
224 break;
227 return 0;
231 /* this is called by ap1000/bif.c when a open reply comes in */
232 void ap_open_reply(struct cap_request *creq)
234 int minor = creq->data[0];
236 ap_fds[minor] = creq->data[1];
237 ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT;
239 #if AP_DEBUG
240 printk("ap opened minor %d length=%d fd=%d\n",
241 minor,ap_length[minor],ap_fds[minor]);
242 #endif
244 wake_up(&busy_wait);
247 static struct file_operations ap_fops = {
248 NULL, /* lseek - default */
249 block_read, /* read - general block-dev read */
250 block_write, /* write - general block-dev write */
251 NULL, /* readdir - bad */
252 NULL, /* poll */
253 ap_ioctl, /* ioctl */
254 NULL, /* mmap */
255 ap_open, /* open */
256 NULL, /* flush */
257 ap_release, /* module needs to decrement use count */
258 block_fsync, /* fsync */
262 int ap_init(void)
264 int i;
265 static int done = 0;
267 if (done) return(1);
269 if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) {
270 printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR);
271 return -1;
273 printk("ap_init: register dev %d\n", MAJOR_NR);
274 blk_dev[MAJOR_NR].request_fn = &ap_request;
276 for (i=0;i<NUM_APDEVS;i++) {
277 ap_blocksizes[i] = AP_BLOCK_SIZE;
278 ap_length[i] = 0;
279 ap_fds[i] = -1;
282 blksize_size[MAJOR_NR] = ap_blocksizes;
284 read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
286 return(0);
289 /* loadable module support */
291 #ifdef MODULE
293 int init_module(void)
295 int error = ap_init();
296 if (!error)
297 printk(KERN_INFO "APBLOCK: Loaded as module.\n");
298 return error;
301 /* Before freeing the module, invalidate all of the protected buffers! */
302 void cleanup_module(void)
304 int i;
306 for (i = 0 ; i < NUM_APDEVS; i++)
307 invalidate_buffers(MKDEV(MAJOR_NR, i));
309 unregister_blkdev( MAJOR_NR, "apblock" );
310 blk_dev[MAJOR_NR].request_fn = 0;
313 #endif /* MODULE */