diff --git a/elks/arch/i86/drivers/char/Makefile b/elks/arch/i86/drivers/char/Makefile index fda253028..17490338f 100644 --- a/elks/arch/i86/drivers/char/Makefile +++ b/elks/arch/i86/drivers/char/Makefile @@ -37,6 +37,10 @@ include $(BASEDIR)/Makefile-rules OBJS = init.o mem.o ntty.o meta.o tcpdev.o pty.o lp.o +ifeq ($(CONFIG_ETH), y) + OBJS += eth.o +endif + ifeq ($(CONFIG_ARCH_8018X), y) CONIO = 8018x SERIAL = template diff --git a/elks/arch/i86/drivers/char/eth.c b/elks/arch/i86/drivers/char/eth.c new file mode 100644 index 000000000..736c0c1b1 --- /dev/null +++ b/elks/arch/i86/drivers/char/eth.c @@ -0,0 +1,123 @@ +/* + * ELKS Ethernet char device driver + * June 2022 Greg Haerr + */ + +#include +#include +#include +#include +#include + +/* character devices and their minor numbers */ +extern struct file_operations ne2k_fops; /* 0 CONFIG_ETH_NE2K */ +extern struct file_operations wd_fops; /* 1 CONFIG_ETH_WD */ +extern struct file_operations el3_fops; /* 2 CONFIG_ETH_EL3 */ + +#define MAX_ETHS 3 + +struct eth { + struct file_operations *ops; +}; +static struct eth eths[MAX_ETHS]; + +/* return file_operations pointer from minor number */ +static struct file_operations *get_ops(dev_t dev) +{ + struct eth *eth = ðs[0]; + unsigned short minor = MINOR(dev); + + do { + if ((eth - eths) == minor) + return eth->ops; + } while (++eth < ðs[MAX_ETHS]); + + return NULL; +} + +static int eth_open(struct inode *inode, struct file *file) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return -ENODEV; + + printk("ETH open pid %d\n", current->pid); + return ops->open(inode, file); +} + +static void eth_release(struct inode *inode, struct file *file) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return; + + printk("ETH close pid %d\n", current->pid); + ops->release(inode, file); +} + +static size_t eth_write(struct inode *inode, struct file *file, char *data, size_t len) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return -ENODEV; + return ops->write(inode, file, data, len); +} + +static size_t eth_read(struct inode *inode, struct file *file, char *data, size_t len) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return -ENODEV; + return ops->read(inode, file, data, len); +} + +static int eth_ioctl(struct inode *inode, struct file *file, int cmd, char *arg) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return -ENODEV; + return ops->ioctl(inode, file, cmd, arg); +} + +static int eth_select(struct inode *inode, struct file *file, int sel_type) +{ + struct file_operations *ops = get_ops(inode->i_rdev); + + if (!ops) + return -ENODEV; + return ops->select(inode, file, sel_type); +} + +static struct file_operations eth_fops = { + NULL, /* lseek */ + eth_read, + eth_write, + NULL, /* readdir */ + eth_select, + eth_ioctl, + eth_open, + eth_release +}; + +void /*INITPROC*/ eth_init(void) +{ + register_chrdev(ETH_MAJOR, "eth", ð_fops); + +#ifdef CONFIG_ETH_NE2K + eths[0].ops = &ne2k_fops; + ne2k_drv_init(); +#endif +#ifdef CONFIG_ETH_WD + eths[1].ops = &wd_fops; + wd_drv_init(); +#endif +#ifdef CONFIG_ETH_EL3 + eths[2].ops = &el3_fops; + el3_drv_init(); +#endif +} diff --git a/elks/arch/i86/drivers/net/Makefile b/elks/arch/i86/drivers/net/Makefile index cb967f0f8..199fbdc86 100644 --- a/elks/arch/i86/drivers/net/Makefile +++ b/elks/arch/i86/drivers/net/Makefile @@ -27,7 +27,7 @@ include $(BASEDIR)/Makefile-rules ######################################################################### # Specific rules. -OBJS = net_drv.o +OBJS = ifeq ($(CONFIG_ETH_NE2K), y) OBJS += ne2k-asm.o ne2k.o endif diff --git a/elks/arch/i86/drivers/net/el3.c b/elks/arch/i86/drivers/net/el3.c index 138a5a015..1e3495d8f 100644 --- a/elks/arch/i86/drivers/net/el3.c +++ b/elks/arch/i86/drivers/net/el3.c @@ -116,14 +116,14 @@ int net_port = EL3_PORT; /* default IO PORT, changed by netport= in /bootopts */ struct netif_stat netif_stat = { 0, 0, 0, 0, 0, 0, {0x52, 0x54, 0x00, 0x12, 0x34, 0x57}}; /* QEMU default + 1 */ static int ioaddr; // FIXME remove later -static int usecount = 0; +static unsigned char usecount; -struct wait_queue rxwait; -struct wait_queue txwait; +static struct wait_queue rxwait; +static struct wait_queue txwait; static word_t el3_id_port; -static struct file_operations el3_fops = +struct file_operations el3_fops = { NULL, /* lseek */ el3_read, @@ -136,20 +136,7 @@ static struct file_operations el3_fops = }; void el3_drv_init( void ) { - int err; - ioaddr = net_port; // temporary - err = request_irq(net_irq, el3_int, INT_GENERIC); - if (err) { - printk("eth: Cannot allocate IRQ %d for EL3: %i\n", - net_irq, err); - return; - } - err = register_chrdev(ETH_MAJOR, "eth", &el3_fops); - if (err) { - printk("eth: device registration error: %i\n", err); - return; - } // May want to probe before requesting the IRQ & device, but // then we need a tiny probe routine, not the whole shebang. @@ -524,6 +511,8 @@ static void el3_release(struct inode *inode, struct file *file) /* But we explicitly zero the IRQ line select anyway */ outw(0x0f00, ioaddr + WN0_IRQ); + + free_irq(net_irq); } return; } @@ -608,7 +597,7 @@ static void el3_down( void ) static int el3_open(struct inode *inode, struct file *file) { - int i; + int i, err; char *mac_addr = (char *)&netif_stat.mac_addr; if (!(netif_stat.if_status & NETIF_FOUND)) @@ -616,6 +605,11 @@ static int el3_open(struct inode *inode, struct file *file) if (usecount++) return(0); // Already open + err = request_irq(net_irq, el3_int, INT_GENERIC); + if (err) { + printk("eth: EL3 unable to use IRQ %d (errno %d)\n", net_irq, err); + return err; + } EL3WINDOW(0); // TESTING ONLY /* Activating the board - done in _init, repeat doesn't harm */ outw(ENABLE_ADAPTER, ioaddr + WN0_CONF_CTRL); diff --git a/elks/arch/i86/drivers/net/ne2k.c b/elks/arch/i86/drivers/net/ne2k.c index 2754d1994..1f80b53d5 100644 --- a/elks/arch/i86/drivers/net/ne2k.c +++ b/elks/arch/i86/drivers/net/ne2k.c @@ -30,9 +30,9 @@ int net_port = NE2K_PORT; /* default IO PORT, changed by netport= in /bootopts * struct netif_stat netif_stat = { 0, 0, 0, 0, 0, 0, {0x52, 0x54, 0x00, 0x12, 0x34, 0x57}}; /* QEMU default + 1 */ -static int usecount = 0; -struct wait_queue rxwait; -struct wait_queue txwait; +static unsigned char usecount; +static struct wait_queue rxwait; +static struct wait_queue txwait; extern word_t _ne2k_next_pk; extern word_t _ne2k_is_8bit; @@ -306,6 +306,11 @@ static int ne2k_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int ne2k_open(struct inode *inode, struct file *file) { if (usecount++ == 0) { // Don't initialize if already open + int err = request_irq(net_irq, ne2k_int, INT_GENERIC); + if (err) { + printk("eth: NE2K unable to use IRQ %d (errno %d)\n", net_irq, err); + return err; + } ne2k_reset(); ne2k_init(); ne2k_start(); @@ -319,16 +324,17 @@ static int ne2k_open(struct inode *inode, struct file *file) static void ne2k_release(struct inode *inode, struct file *file) { - if (--usecount == 0) + if (--usecount == 0) { ne2k_stop(); - + free_irq(net_irq); + } } /* * Ethernet operations */ -static struct file_operations ne2k_fops = +struct file_operations ne2k_fops = { NULL, /* lseek */ ne2k_read, @@ -399,17 +405,6 @@ void ne2k_drv_init(void) printk("eth: NE2K not found at 0x%x, irq %d\n", net_port, net_irq); break; } - err = request_irq(net_irq, ne2k_int, INT_GENERIC); - if (err) { - printk("eth: NE2K IRQ %d request error: %i\n", net_irq, err); - break; - } - - err = register_chrdev(ETH_MAJOR, "eth", &ne2k_fops); - if (err) { - printk("eth: register error: %i\n", err); - break; - } cprom = (byte_t *)prom; diff --git a/elks/arch/i86/drivers/net/net_drv.c b/elks/arch/i86/drivers/net/net_drv.c deleted file mode 100644 index c094a828e..000000000 --- a/elks/arch/i86/drivers/net/net_drv.c +++ /dev/null @@ -1,17 +0,0 @@ -/* Initialize Ethernet driver */ - -#include -#include - -void eth_init(void) -{ -#ifdef CONFIG_ETH_NE2K - ne2k_drv_init(); -#endif -#ifdef CONFIG_ETH_WD - wd_drv_init(); -#endif -#ifdef CONFIG_ETH_EL3 - el3_drv_init(); -#endif -} diff --git a/elks/arch/i86/drivers/net/wd.c b/elks/arch/i86/drivers/net/wd.c index 665e5c989..8e4842862 100644 --- a/elks/arch/i86/drivers/net/wd.c +++ b/elks/arch/i86/drivers/net/wd.c @@ -139,6 +139,7 @@ static unsigned char current_rx_page = WD_FIRST_RX_PG; static word_t wd_rx_stat(void); static word_t wd_tx_stat(void); +static void wd_int(int irq, struct pt_regs * regs); /* * Get MAC @@ -492,6 +493,11 @@ static int wd_open(struct inode * inode, struct file * file) err = -EBUSY; break; } + err = request_irq(net_irq, wd_int, INT_GENERIC); + if (err) { + printk("eth: WD unable to use IRQ %d (errno %d)\n", net_irq, err); + break; + } wd_reset(); wd_init(); if (INB(net_port + 14U) & 0x20U) /* enable IRQ on softcfg card */ @@ -510,6 +516,7 @@ static void wd_release(struct inode * inode, struct file * file) { wd_stop(); wd_term(); + free_irq(net_irq); wd_inuse = 0U; } @@ -517,7 +524,7 @@ static void wd_release(struct inode * inode, struct file * file) * Ethernet operations */ -static struct file_operations wd_fops = +struct file_operations wd_fops = { NULL, /* lseek */ wd_read, @@ -574,22 +581,10 @@ static void wd_int(int irq, struct pt_regs * regs) void wd_drv_init(void) { - int err; unsigned u; word_t hw_addr[6U]; do { - err = request_irq(net_irq, wd_int, INT_GENERIC); - if (err) { - printk("eth: WD IRQ %d request error: %i\n", - net_irq, err); - break; - } - err = register_chrdev(ETH_MAJOR, "eth", &wd_fops); - if (err) { - printk("eth: register error: %i\n", err); - break; - } wd_get_hw_addr(hw_addr); for (u = 0U; u < 6U; u++) mac_addr[u] = (hw_addr[u] & 0xffU); diff --git a/elks/arch/i86/kernel/irq-8018x.c b/elks/arch/i86/kernel/irq-8018x.c index d05329251..7f71d3a17 100644 --- a/elks/arch/i86/kernel/irq-8018x.c +++ b/elks/arch/i86/kernel/irq-8018x.c @@ -88,6 +88,11 @@ int remap_irq(int irq) return irq; } +void disable_irq(unsigned int irq) +{ + // TODO disable passed interrupt +} + // Get interrupt vector from IRQ int irq_vector(int irq) { diff --git a/elks/arch/i86/kernel/irq-8259.c b/elks/arch/i86/kernel/irq-8259.c index 4a1e78fa6..8f0a3204f 100644 --- a/elks/arch/i86/kernel/irq-8259.c +++ b/elks/arch/i86/kernel/irq-8259.c @@ -66,7 +66,6 @@ int irq_vector (int irq) return irq + ((irq >= 8) ? 0x68 : 0x08); } -#if 0 void disable_irq(unsigned int irq) { flag_t flags; @@ -85,4 +84,3 @@ void disable_irq(unsigned int irq) } restore_flags(flags); } -#endif diff --git a/elks/arch/i86/kernel/irq.c b/elks/arch/i86/kernel/irq.c index c27a4205c..af14d8c9f 100644 --- a/elks/arch/i86/kernel/irq.c +++ b/elks/arch/i86/kernel/irq.c @@ -110,11 +110,11 @@ int request_irq(int irq, irq_handler handler, int hflag) return 0; } -#if 0 void free_irq(unsigned int irq) { flag_t flags; + irq = remap_irq(irq); if (irq > 15) { printk("Trying to free IRQ%u\n",irq); return; @@ -132,7 +132,6 @@ void free_irq(unsigned int irq) restore_flags(flags); } -#endif /* * IRQ setup. diff --git a/elks/include/arch/irq.h b/elks/include/arch/irq.h index c3d79fe81..4494a2a2e 100644 --- a/elks/include/arch/irq.h +++ b/elks/include/arch/irq.h @@ -13,6 +13,7 @@ typedef void (* irq_handler) (int,struct pt_regs *); // IRQ handler void do_IRQ(int,void *); int request_irq(int,irq_handler,int hflag); +void free_irq(unsigned int irq); void int_vector_set (int vect, int_proc proc, int seg); void _irqit (void); @@ -20,6 +21,7 @@ void _irqit (void); /* irq-8259.c*/ void init_irq(void); void enable_irq(unsigned int); +void disable_irq(unsigned int irq); int remap_irq(int); int irq_vector (int irq);