You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1253 lines
29 KiB

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
//#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <vm/vm.h>
#include <include/autoconf.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include<linux/io.h>
#include <stdlib.h>
#ifdef BONITOEL
#include <include/bonito.h>
#endif
#include <target/sbd.h>
#define HZ 100
#define printk printf
#define FDF_LOADED 0x10
#define DBG(x...) printf("%s,%d:%s\n",__FILE__,__LINE__,x)
#define DEVICE_INTR do_floppy
#define BLOCK_SIZE 1024
#define DEVICE_NAME "fd"
#define READ 0
#define WRITE 1
#define wdlookup(unit) (struct wd_softc *)device_lookup(&wd_cd, (unit))
#define RQ_INACTIVE (-1)
#define RQ_ACTIVE 1
#define RQ_SCSI_BUSY 0xffff
#define RQ_SCSI_DONE 0xfffe
#define RQ_SCSI_DISCONNECTING 0xffe0
struct inode{
int i_rdev;
};
typedef int kdev_t;
struct buffer_head {
struct buffer_head *b_next; /* Hash queue list */
unsigned long b_blocknr; /* block number */
unsigned short b_size; /* block size */
unsigned short b_list; /* List that this buffer appears */
kdev_t b_dev; /* device (B_FREE = free) */
kdev_t b_rdev; /* Real device */
unsigned long b_state; /* buffer state bitmap (see above) */
struct {
caddr_t b_addr; /* Memory, superblocks, indirect etc. */
} b_un;
void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
void *b_private; /* reserved for b_end_io */
void *b_journal_head; /* ext3 journal_heads */
unsigned long b_rsector; /* Real buffer location on disk */
struct buf *bp;
};
/* bh state bits */
enum bh_state_bits {
BH_Uptodate, /* 1 if the buffer contains valid data */
BH_Dirty, /* 1 if the buffer is dirty */
BH_Lock, /* 1 if the buffer is locked */
BH_Req, /* 0 if the buffer has been invalidated */
BH_Mapped, /* 1 if the buffer has a disk mapping */
BH_New, /* 1 if the buffer is new and not yet written out */
BH_Async, /* 1 if the buffer is under end_buffer_io_async I/O */
BH_Wait_IO, /* 1 if we should write out this buffer */
BH_Launder, /* 1 if we can throttle on this buffer */
BH_Attached, /* 1 if b_inode_buffers is linked into a list */
BH_JBD, /* 1 if it has an attached journal_head */
BH_Sync, /* 1 if the buffer is a sync read */
BH_Delay, /* 1 if the buffer is delayed allocate */
BH_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
*/
};
struct request {
volatile int rq_status; /* should split this into a few status bits */
#define RQ_INACTIVE (-1)
#define RQ_ACTIVE 1
#define RQ_SCSI_BUSY 0xffff
#define RQ_SCSI_DONE 0xfffe
#define RQ_SCSI_DISCONNECTING 0xffe0
kdev_t rq_dev;
int cmd; /* READ or WRITE */
int errors;
unsigned long start_time;
unsigned long sector;
unsigned long nr_sectors;
unsigned long hard_sector, hard_nr_sectors;
unsigned int nr_segments;
unsigned int nr_hw_segments;
unsigned long current_nr_sectors, hard_cur_sectors;
void * special;
char * buffer;
int * waiting;
struct buffer_head * bh;
struct buffer_head * bhtail;
// struct request * next;
};
struct hw_interrupt_type {
const char * typename;
unsigned int (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);
void (*end)(unsigned int irq);
void (*set_affinity)(unsigned int irq, unsigned long mask);
};
//-----------------------------------------------------------------------
extern int ticks;
inline int lock_fdc(int drive,int flags){return 0;}
#define unlock_fdc(...)
#define spin_lock_irqsave(...)
#define spin_unlock_irqrestore(...)
#define request_region(...) 1
#define release_region(...)
#define devfs_register(...)
#define devfs_mk_dir(...) 0
#define devfs_register_blkdev(...) 0
#define devfs_unregister_blkdev(...)
#define blk_cleanup_queue(...)
#define DECLARE_WAITQUEUE(q,t) int q
#define __init
#define KERN_INFO
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#define kmalloc(size,type) malloc(size)
typedef int devfs_handle_t;
typedef int spinlock_t;
typedef int64_t u64;
#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
#define virt_to_bus(x) (PHYSADDR((x)))
#define test_and_clear_bit clear_bit
#define test_and_set_bit set_bit
extern __inline__ int set_bit(int nr,long * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
// cli();
retval = (mask & *addr) != 0;
*addr |= mask;
// sti();
return retval;
}
extern __inline__ int clear_bit(int nr, long * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
// cli();
retval = (mask & *addr) != 0;
*addr &= ~mask;
// sti();
return retval;
}
extern __inline__ int test_bit(int nr, long * addr)
{
int mask;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
//----------------------------------------------------------------------------------
#define HZ 100
extern __inline__ void
__delay(unsigned long loops)
{
__asm__ __volatile__ (
".set\tnoreorder\n"
"1:\tbnez\t%0,1b\n\t"
"subu\t%0,1\n\t"
".set\treorder"
:"=r" (loops)
:"0" (loops));
}
/*
* Division by multiplication: you don't have to worry about
* loss of precision.
*
* Use only for very small delays ( < 1 msec). Should probably use a
* lookup table, really, as the multiplications take much too long with
* short delays. This is a "reasonable" implementation, though (and the
* first constant multiplications gets optimized away if the delay is
* a constant)
*/
extern __inline__ void __udelay(unsigned long usecs, unsigned long lpj)
{
unsigned long lo;
/*
* Excessive precission? Probably ...
*/
usecs *= (unsigned long) (((0x8000000000000000ULL / (500000 / HZ)) +
0x80000000ULL) >> 32);
__asm__("multu\t%2,%3"
:"=h" (usecs), "=l" (lo)
:"r" (usecs),"r" (lpj));
__delay(usecs);
}
extern __inline__ void __ndelay(unsigned long nsecs, unsigned long lpj)
{
unsigned long lo;
/*
* Excessive precission? Probably ...
*/
nsecs *= (unsigned long) (((0x8000000000000000ULL / (500000000 / HZ)) +
0x80000000ULL) >> 32);
__asm__("multu\t%2,%3"
:"=h" (nsecs), "=l" (lo)
:"r" (nsecs),"r" (lpj));
__delay(nsecs);
}
#define __udelay_val 1024
#define udelay(usecs) __udelay((usecs),__udelay_val)
#define ndelay(nsecs) __ndelay((nsecs),__udelay_val)
#define FD_RESET_DELAY 20
//---------------------------------------------------------------------
#include "dma.h"
struct fd_ops {
unsigned char (*fd_inb)(unsigned int port);
void (*fd_outb)(unsigned char value, unsigned int port);
/*
* How to access the floppy DMA functions.
*/
void (*fd_enable_dma)(int channel);
void (*fd_disable_dma)(int channel);
int (*fd_request_dma)(int channel);
void (*fd_free_dma)(int channel);
void (*fd_clear_dma_ff)(int channel);
void (*fd_set_dma_mode)(int channel, char mode);
void (*fd_set_dma_addr)(int channel, unsigned int a);
void (*fd_set_dma_count)(int channel, unsigned int count);
int (*fd_get_dma_residue)(int channel);
void (*fd_enable_irq)(int irq);
void (*fd_disable_irq)(int irq);
unsigned long (*fd_getfdaddr1)(void);
unsigned long (*fd_dma_mem_alloc)(unsigned long size);
void (*fd_dma_mem_free)(unsigned long addr, unsigned long size);
unsigned long (*fd_drive_type)(unsigned long);
};
extern struct fd_ops *fd_ops;
#define fd_inb(port) fd_ops->fd_inb(port)
#define fd_outb(value,port) fd_ops->fd_outb(value,port)
#define fd_enable_dma() fd_ops->fd_enable_dma(FLOPPY_DMA)
#define fd_disable_dma() fd_ops->fd_disable_dma(FLOPPY_DMA)
#define fd_request_dma() fd_ops->fd_request_dma(FLOPPY_DMA)
#define fd_free_dma() fd_ops->fd_free_dma(FLOPPY_DMA)
#define fd_clear_dma_ff() fd_ops->fd_clear_dma_ff(FLOPPY_DMA)
#define fd_set_dma_mode(mode) fd_ops->fd_set_dma_mode(FLOPPY_DMA, mode)
#define fd_set_dma_addr(addr) fd_ops->fd_set_dma_addr(FLOPPY_DMA, \
virt_to_bus(addr))
#define fd_set_dma_count(count) fd_ops->fd_set_dma_count(FLOPPY_DMA,count)
#define fd_get_dma_residue() fd_ops->fd_get_dma_residue(FLOPPY_DMA)
#define fd_enable_irq() fd_ops->fd_enable_irq(FLOPPY_IRQ)
#define fd_disable_irq() fd_ops->fd_disable_irq(FLOPPY_IRQ)
#define fd_dma_mem_alloc(size) fd_ops->fd_dma_mem_alloc(size)
#define fd_dma_mem_free(mem,size) fd_ops->fd_dma_mem_free(mem,size)
#define fd_drive_type(n) fd_ops->fd_drive_type(n)
#define fd_cacheflush(addr,size) CPU_FlushCache() //flushdcache(addr,size)//CPU_FlushDCache(addr,size);
#define MAX_BUFFER_SECTORS 24
/*
* And on Mips's the CMOS info fails also ...
*
* FIXME: This information should come from the ARC configuration tree
* or whereever a particular machine has stored this ...
*/
#define FLOPPY0_TYPE fd_drive_type(0)
#define FLOPPY1_TYPE fd_drive_type(1)
#define FDC1 fd_ops->fd_getfdaddr1();
#define N_FDC 1 /* do you *really* want a second controller? */
#define N_DRIVE 8
#define FLOPPY_MOTOR_MASK 0xf0
/*
* The DMA channel used by the floppy controller cannot access data at
* addresses >= 16MB
*
* Went back to the 1MB limit, as some people had problems with the floppy
* driver otherwise. It doesn't matter much for performance anyway, as most
* floppy accesses go through the track buffer.
*
* On MIPSes using vdma, this actually means that *all* transfers go thru
* the * track buffer since 0x1000000 is always smaller than KSEG0/1.
* Actually this needs to be a bit more complicated since the so much different
* hardware available with MIPS CPUs ...
*/
#define CROSS_64KB(a,s) ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)
#define EXTRA_FLOPPY_PARAMS
//------------------------------------------------------------------------
#define mark_bh(...)
#define fdlookup(unit) (struct fd_softc *)device_lookup(&fd_cd, (unit))
typedef struct request *request_queue_t;
#define CURRENT current_request
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
#define LOCAL_END_REQUEST
extern int floppy_init(void);
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
/*
* end_request() and friends. Must be called with the request queue spinlock
* acquired. All functions called within end_request() _must_be_ atomic.
*
* Several drivers define their own end_request and call
* end_that_request_first() and end_that_request_last()
* for parts of the original function. This prevents
* code duplication in drivers.
*/
int end_that_request_first(struct request *req, int uptodate, char *name);
void end_that_request_last(struct request *req);
#undef DEVICE_ON
#undef DEVICE_OFF
/*
* Add entries as needed.
*/
static void floppy_off(unsigned int nr);
//#define DEVICE_NAME "floppy"
#define MAJOR(dev) ((dev)>>8)
#define MINOR(dev) ((dev) & 0xff)
#define MKDEV(ma,mi) ((ma)<<8 | (mi))
#define DEVICE_INTR do_floppy
#define DEVICE_REQUEST do_fd_request
#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
/* provide DEVICE_xxx defaults, if not explicitly defined
* above in the MAJOR_NR==xxx if-elif tree */
#ifndef DEVICE_ON
#define DEVICE_ON(device) do {} while (0)
#endif
#ifndef DEVICE_OFF
#define DEVICE_OFF(device) do {} while (0)
#endif
#ifndef QUEUE_EMPTY
#define QUEUE_EMPTY (!CURRENT)
#endif
#ifndef DEVICE_NAME
#define DEVICE_NAME "unknown"
#endif
#ifdef DEVICE_INTR
static void (*DEVICE_INTR)(void) = NULL;
#endif
#define SET_INTR(x) (DEVICE_INTR = (x))
#ifdef DEVICE_REQUEST
static void (DEVICE_REQUEST)(request_queue_t *);
#endif
#ifdef DEVICE_INTR
#define CLEAR_INTR SET_INTR(NULL)
#else
#define CLEAR_INTR
#endif
#define INIT_REQUEST \
if (QUEUE_EMPTY) {\
CLEAR_INTR; \
return; \
}
static int floppy_open(struct inode * inode);
static int floppy_release(struct inode * inode);
#include "fd.h"
#include "fdreg.h"
#include "dma.h"
#define SPIN_LOCK_UNLOCKED 1
//-------------------------------------------------------------------------------------
void enable_8259A_irq(unsigned int irq);
void disable_8259A_irq(unsigned int irq);
/*
* This is the 'legacy' 8259A Programmable Interrupt Controller,
* present in the majority of PC/AT boxes.
* plus some generic x86 specific things if generic specifics makes
* any sense at all.
* this file should become arch/i386/kernel/irq.c when the old irq.c
* moves to arch independent land
*/
static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
static void end_8259A_irq (unsigned int irq)
{
enable_8259A_irq(irq);
}
#define shutdown_8259A_irq disable_8259A_irq
void mask_and_ack_8259A(unsigned int);
static unsigned int startup_8259A_irq(unsigned int irq)
{
enable_8259A_irq(irq);
// prom_printf("8259 irq %x enabled\n", irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type i8259A_irq_type = {
"XT-PIC",
startup_8259A_irq,
shutdown_8259A_irq,
enable_8259A_irq,
disable_8259A_irq,
mask_and_ack_8259A,
end_8259A_irq,
NULL
};
/*
* 8259A PIC functions to handle ISA devices:
*/
/*
* This contains the irq mask for both 8259A irq controllers,
*/
static unsigned int cached_irq_mask = 0xffff;
#define cached_21 (cached_irq_mask)
#define cached_A1 (cached_irq_mask >> 8)
void disable_8259A_irq(unsigned int irq)
{
unsigned int mask = 1 << irq;
unsigned long flags;
cached_irq_mask |= mask;
if (irq & 8)
linux_outb(cached_A1,0xA1);
else
linux_outb(cached_21,0x21);
}
void enable_8259A_irq(unsigned int irq)
{
unsigned int mask = ~(1 << irq);
unsigned long flags;
cached_irq_mask &= mask;
if (irq & 8)
linux_outb(cached_A1,0xA1);
else
linux_outb(cached_21,0x21);
}
int i8259A_irq_pending(unsigned int irq)
{
unsigned int mask = 1 << irq;
unsigned long flags;
int ret;
if (irq < 8)
ret = linux_inb(0x20) & mask;
else
ret = linux_inb(0xA0) & (mask >> 8);
return ret;
}
/*
* This function assumes to be called rarely. Switching between
* 8259A registers is slow.
* This has to be protected by the irq controller spinlock
* before being called.
*/
static inline int i8259A_irq_real(unsigned int irq)
{
int value;
int irqmask = 1 << irq;
if (irq < 8) {
linux_outb(0x0B,0x20); /* ISR register */
value = linux_inb(0x20) & irqmask;
linux_outb(0x0A,0x20); /* back to the IRR register */
return value;
}
linux_outb(0x0B,0xA0); /* ISR register */
value = linux_inb(0xA0) & (irqmask >> 8);
linux_outb(0x0A,0xA0); /* back to the IRR register */
return value;
}
/*
* Careful! The 8259A is a fragile beast, it pretty
* much _has_ to be done exactly like this (mask it
* first, _then_ send the EOI, and the order of EOI
* to the two 8259s is important!
*/
void mask_and_ack_8259A(unsigned int irq)
{
unsigned int irqmask = 1 << irq;
unsigned long flags;
/*
* Lightweight spurious IRQ detection. We do not want to overdo
* spurious IRQ handling - it's usually a sign of hardware problems, so
* we only do the checks we can do without slowing down good hardware
* nnecesserily.
*
* Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting
* rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A.
* Thus we can check spurious 8259A IRQs without doing the quite slow
* i8259A_irq_real() call for every IRQ. This does not cover 100% of
* spurious interrupts, but should be enough to warn the user that
* there is something bad going on ...
*/
if (cached_irq_mask & irqmask)
goto spurious_8259A_irq;
cached_irq_mask |= irqmask;
handle_real_irq:
if (irq & 8) {
linux_inb(0xA1); /* DUMMY - (do we need this?) */
linux_outb(cached_A1,0xA1);
linux_outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
linux_outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
} else {
linux_inb(0x21); /* DUMMY - (do we need this?) */
linux_outb(cached_21,0x21);
linux_outb(0x60+irq,0x20); /* 'Specific EOI' to master */
}
return;
spurious_8259A_irq:
/*
* this is the slow path - should happen rarely.
*/
if (i8259A_irq_real(irq))
/*
* oops, the IRQ _is_ in service according to the
* 8259A - not spurious, go handle it.
*/
goto handle_real_irq;
{
static int spurious_irq_mask = 0;
/*
* At this point we can be sure the IRQ is spurious,
* lets ACK and report it. [once per IRQ]
*/
if (!(spurious_irq_mask & irqmask)) {
printk("spurious 8259A interrupt: IRQ%d.\n", irq);
spurious_irq_mask |= irqmask;
}
/*
* Theoretically we do not have to handle this IRQ,
* but in Linux this does not cause problems and is
* simpler for us.
*/
goto handle_real_irq;
}
}
void init_8259A(int auto_eoi)
{
linux_outb(0xff, 0x21); /* mask all of 8259A-1 */
linux_outb(0xff, 0xA1); /* mask all of 8259A-2 */
/*
* linux_outb_p - this has to work on a wide range of PC hardware.
*/
linux_outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */
linux_outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */
linux_outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */
if (auto_eoi)
linux_outb_p(0x03, 0x21); /* master does Auto EOI */
else
linux_outb_p(0x01, 0x21); /* master expects normal EOI */
linux_outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */
linux_outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */
linux_outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */
linux_outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode
is to be investigated) */
if (auto_eoi)
/*
* in AEOI mode we just have to mask the interrupt
* when acking.
*/
i8259A_irq_type.ack = disable_8259A_irq;
else
i8259A_irq_type.ack = mask_and_ack_8259A;
udelay(100); /* wait for 8259A to initialize */
linux_outb(cached_21, 0x21); /* restore master IRQ mask */
linux_outb(cached_A1, 0xA1); /* restore slave IRQ mask */
}
/*
* On systems with i8259-style interrupt controllers we assume for
* driver compatibility reasons interrupts 0 - 15 to be the i8295
* interrupts even if the hardware uses a different interrupt numbering.
*/
void init_i8259_irqs (void)
{
init_8259A(0);
i8259A_irq_type.startup(2);
}
//-----------------------------------------------------------------------------------
#if 1
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#ifndef IDE_PORT_FIX1
#define IDE_PORT_FIX1 0x3f50 //0xff10
#define IDE_PORT_FIX2 0x3f60 //0xff80
#endif
void fixup_ide()
{
pcitag_t pdev;
int i;
for(i=0;i<32;i++)
{
/*82371 fixup*/
pdev=_pci_make_tag(0,i,1);
if(_pci_conf_read(pdev,0)==0x71118086)
{
_pci_conf_write(pdev,0x20,IDE_PORT_FIX1);
pdev=_pci_make_tag(0,i,2);
_pci_conf_write(pdev,0x20,IDE_PORT_FIX2);
break;
}
}
}
#endif
//----------------------------------------------------------------------------------
static unsigned char std_fd_inb(unsigned int port)
{
// myprintf("std_fd_inb(0x%x)\n",port);
return linux_inb(port);
}
static void std_fd_outb(unsigned char value, unsigned int port)
{
// myprintf("std_fd_out(0x%x,0x%x)\n",value,port);
linux_outb(value, port);
}
/*
* How to access the floppy DMA functions.
*/
static void std_fd_enable_dma(int channel)
{
enable_dma(channel);
}
static void std_fd_disable_dma(int channel)
{
disable_dma(channel);
}
static int std_fd_request_dma(int channel)
{
return 0;//request_dma(channel, "floppy");
}
static void std_fd_free_dma(int channel)
{
//free_dma(channel);
}
static void std_fd_clear_dma_ff(int channel)
{
clear_dma_ff(channel);
}
static void std_fd_set_dma_mode(int channel, char mode)
{
set_dma_mode(channel, mode);
}
static void std_fd_set_dma_addr(int channel, unsigned int addr)
{
set_dma_addr(channel, addr);
}
static void std_fd_set_dma_count(int channel, unsigned int count)
{
set_dma_count(channel, count);
}
static int std_fd_get_dma_residue(int channel)
{
return get_dma_residue(channel);
}
static void std_fd_enable_irq(int irq)
{
i8259A_irq_type.enable(irq);
}
static void std_fd_disable_irq(int irq)
{
i8259A_irq_type.disable(irq);
}
static unsigned long std_fd_getfdaddr1(void)
{
return 0x3f0;
}
#define USE_MY_ALLOC
#ifdef USE_MY_ALLOC
static unsigned long fd_dma_base=0x80800000;
#else
static unsigned long realmem;
#endif
static unsigned long std_fd_dma_mem_alloc(unsigned long size)
{
long mem;
#ifdef USE_MY_ALLOC
mem=fd_dma_base;
fd_dma_base +=size;
#else
realmem=malloc(size+0x10000);
mem=(realmem+0x10000-1)&~(0x10000-1);
#endif
return mem;
}
static void std_fd_dma_mem_free(unsigned long addr, unsigned long size)
{
#ifdef USE_MY_ALLOC
if(fd_dma_base==(addr+size))fd_dma_base=addr;
#else
free(realmem);
#endif
}
static unsigned long std_fd_drive_type(unsigned long n)
{
if (n == 0)
return 4; /* 3,5", 1.44mb */
return 0;
}
struct fd_ops std_fd_ops = {
/*
* How to access the floppy controller's ports
*/
std_fd_inb,
std_fd_outb,
/*
* How to access the floppy DMA functions.
*/
std_fd_enable_dma,
std_fd_disable_dma,
std_fd_request_dma,
std_fd_free_dma,
std_fd_clear_dma_ff,
std_fd_set_dma_mode,
std_fd_set_dma_addr,
std_fd_set_dma_count,
std_fd_get_dma_residue,
std_fd_enable_irq,
std_fd_disable_irq,
std_fd_getfdaddr1,
std_fd_dma_mem_alloc,
std_fd_dma_mem_free,
std_fd_drive_type
};
struct fd_ops *fd_ops=&std_fd_ops;
//---------------------------------------------------------------------
struct fd_softc {
/* General disk infos */
struct device sc_dev;
int d_secsize;
int sc_flags;
};
char tmp_floppy_area[1024];
int fdmatch( struct device *parent, void *match, void *aux);
void fdattach(struct device *parent, struct device *self, void *aux);
struct cfattach fd_ca = {
sizeof(struct fd_softc), fdmatch, fdattach,
};
struct cfdriver fd_cd = {
NULL, "fd", DV_DISK
};
struct request *current_request=0;
void *
tgt_poll_register( int level, int(*func) __P((void *)), void *arg);
void floppy_on(unsigned int nr);
void floppy_off(unsigned int nr);
void floppy_off_timer(int nr);
void floppy_on_timer(int nr);
extern struct cfdriver fd_cd;
int ticks_to_floppy_on(unsigned int nr);
extern int command_done;
void wake_up(void *p)
{
int s = splhigh ();
volatile int *ps=p;
*ps=0;
(void) splx (s);
}
void sleep_on(void *p)
{
int s = splhigh ();
volatile int *ps=p;
*ps=1;
do{
idle ();
}while(*ps);
splx(s);
}
void interruptible_sleep_on(void *p)
{
sleep_on(p);
}
#define cli(...)
#define sti(...)
#include "list.h"
struct timer_list {
struct list_head list;
struct timer_list *next;
struct timer_list *prev;
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
};
static inline int timer_pending (const struct timer_list * timer)
{
return timer->list.next != NULL;
}
void add_timer(struct timer_list *timer)
{
timeout(( void (*) __P((void *)))timer->function,(void *)timer->data,timer->expires-ticks);
}
void del_timer(struct timer_list *timer)
{
untimeout(( void (*) __P((void *)))timer->function,(void *)timer->data);
}
typedef struct list_head task_queue;
struct tq_struct {
struct list_head list;
void (*routine)(void *); /* function to call */
int sync;
void *data; /* argument to function */
};
#define TQ_ACTIVE(q) (!list_empty(&q))
static inline int queue_task(struct tq_struct *bh_pointer, task_queue *bh_list)
{
int ret = 0;
if (!test_and_set_bit(0,&bh_pointer->sync)) {
list_add_tail(&bh_pointer->list, bh_list);
ret = 1;
}
return ret;
}
void __run_task_queue(task_queue *list)
{
struct list_head head, *next;
list_add(&head, list);
list_del_init(list);
next = head.next;
while (next != &head) {
void (*f) (void *);
struct tq_struct *p;
void *data;
p = list_entry(next, struct tq_struct, list);
next = next->next;
f = p->routine;
data = p->data;
p->sync = 0;
if (f)
{
f(data);
}
}
}
static inline void run_task_queue(task_queue *list)
{
if (TQ_ACTIVE(*list))
__run_task_queue(list);
}
#define DECLARE_TASK_QUEUE(q) LIST_HEAD1(q)
DECLARE_TASK_QUEUE(tq_immediate);
void fdstrategy(struct buf *bp);
static struct inode inode_fd0={.i_rdev=0x200};
int
fdopen(
dev_t dev,
int flag, int fmt,
struct proc *p)
{
floppy_open(&inode_fd0);
return 0;
}
int floppy_init(void);
int
fdread(
dev_t dev,
struct uio *uio,
int flags)
{
int ret;
ret=physio(fdstrategy, NULL, dev, B_READ, minphys, uio);
return ret;
}
int
fdwrite(
dev_t dev,
struct uio *uio,
int flags)
{
return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
}
int
fdclose( dev_t dev,
int flag, int fmt,
struct proc *p)
{
floppy_release(&inode_fd0);
return 0;
}
int
fdmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct confargs *ca = aux;
int found = 0;
if (strcmp(ca->ca_name, fd_cd.cd_name) != 0)
return (found);
if(!getenv("nofdc"))found=1;
return found;
}
void
fdattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct fd_softc *fd = (void *)self;
fd->d_secsize=0x200;
fd->sc_flags= FDF_LOADED;
enable_dma(4);
fixup_ide();
init_i8259_irqs();
floppy_init();
}
struct buffer_head lcureent_bh;
static void mywakeup(struct buffer_head *bh,int uptodate)
{
if (!uptodate) {
bh->bp->b_flags |= B_ERROR;
}
biodone(bh->bp);
}
void fd_enqueue_request(struct buf *bp)
{
struct buffer_head *bh=&lcureent_bh;
bh->b_size=bp->b_bcount;
bh->b_rsector=bp->b_blkno;
bh->b_rdev=0x200;
bh->b_data=bp->b_data;
bh->b_end_io=mywakeup;
bh->bp=bp;
add_request(bp->b_flags&B_READ?READ:WRITE,bh);
}
extern int usage_count;
static void do_fd_request(request_queue_t * q);
void
fdstrategy(struct buf *bp)
{
struct fd_softc *fd;
int s;
//???
fd = fdlookup(DISKUNIT(bp->b_dev));
if (fd == NULL) {
bp->b_error = ENXIO;
goto bad;
}
/* Valid request? */
if (bp->b_blkno < 0 ||
(bp->b_bcount % fd->d_secsize) != 0 ||
(bp->b_bcount / fd->d_secsize) >= (1 << NBBY)) {
bp->b_error = EINVAL;
goto bad;
}
/* If device invalidated (e.g. media change, door open), error. */
if ((fd->sc_flags & FDF_LOADED) == 0) {
bp->b_error = EIO;
goto bad;
}
/* If it's a null transfer, return immediately. */
if (bp->b_bcount == 0)
goto done;
/*
* Do bounds checking, adjust transfer. if error, process.
* If end of partition, just return.
*/
/* Queue transfer on drive, activate drive and controller if idle. */
s = splbio();
usage_count++;
fd_enqueue_request(bp);//disksort(&fd->sc_q, bp);
usage_count--;
splx(s);
device_unref(&fd->sc_dev);
return;
bad:
bp->b_flags |= B_ERROR;
done:
/* Toss transfer; we're done early. */
bp->b_resid = bp->b_bcount;
biodone(bp);
if (fd != NULL)
device_unref(&fd->sc_dev);
}
#define DECLARE_WAIT_QUEUE_HEAD(x) int x
#define set_current_state(...)
static struct tq_struct floppy_tq;
//device 0xa, crf3
void floppy_interrupt(int irq, void *dev_id, void * regs);
#include "fdreg.h"
static void floppy_interrupt_pmon(void)
{
if(i8259A_irq_pending(FLOPPY_IRQ))
{
i8259A_irq_type.ack(FLOPPY_IRQ);
floppy_interrupt(6,0,0);
i8259A_irq_type.end(FLOPPY_IRQ);
}
run_task_queue(&tq_immediate);
}
int fd_request_irq()
{
static int requested=0;
if(!requested)
{
tgt_poll_register(IPL_BIO,(int(*) __P((void *)))&floppy_interrupt_pmon,0);
requested=1;
}
i8259A_irq_type.startup(FLOPPY_IRQ);
return 0;
}
void fd_free_irq()
{
i8259A_irq_type.shutdown(FLOPPY_IRQ);
}
//----------------------------------------------------------------------
DECLARE_WAIT_QUEUE_HEAD(mywaitqueue);
static void mywakeup1(struct buffer_head *bh,int update)
{
wake_up(&mywaitqueue);
}
void read_a_sector(int block,char *buf)
{
static struct buffer_head mybuffer;
struct buffer_head *bh=&mybuffer;
struct inode inode_fd0;
inode_fd0.i_rdev=0x200;
floppy_open(&inode_fd0);
bh->b_size=512;
bh->b_rsector=block;
bh->b_rdev=0x200;
bh->b_data=buf;
bh->b_end_io=mywakeup1;
add_request(READ,bh);
sleep_on(&mywaitqueue);
floppy_release(&inode_fd0);
}
void write_a_sector(int block,char *buf)
{
static struct buffer_head mybuffer;
struct buffer_head *bh=&mybuffer;
struct inode inode_fd0;
inode_fd0.i_rdev=0x200;
floppy_open(&inode_fd0);
bh->b_size=512;
bh->b_rsector=block;
bh->b_rdev=0x200;
bh->b_data=buf;
bh->b_end_io=mywakeup1;
add_request(WRITE,bh);
sleep_on(&mywaitqueue);
floppy_release(&inode_fd0);
}
static char fdbuf[512];
static int readfd(int argc,char **argv)
{
char str[0x100];
int block;
if(argc>1)block=strtol(argv[1],0,0);
else block=0;
memset(fdbuf,0,512);
read_a_sector(block,fdbuf);
sprintf(str,"pcs -1;d1 %p 256",fdbuf);
printf("%s\n",str);
do_cmd(str);
return 0;
}
static int writefd(int argc,char **argv)
{
int block;
if(argc>1)block=strtol(argv[1],0,0);
else block=0;
write_a_sector(block,fdbuf);
return 0;
}
void setup_fdvar()
{
char str[0x100];
do_cmd("set iomap 0");
sprintf(str,"%p",fdbuf);
setenv("faddr",str);
}
#include <pmon.h>
static const Cmd Cmds[] =
{
{"MyCmds"},
{"readfd","readfd block",0,"read a block from fd",readfd,0,99,CMD_REPEAT},
{"writefd","writefd block",0,"write a block to fd",writefd,0,99,CMD_REPEAT},
{0, 0}
};
static void init_cmd __P((void)) __attribute__ ((constructor));
static void
init_cmd()
{
cmdlist_expand(Cmds, 1);
}