?? parport.c
字號:
/* $Id: parport.c,v 1.1.1.1 2004/02/04 12:55:28 laputa Exp $ * * Elinux parallel port driver * NOTE! * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 * this should be handled if both are enabled at the same time. * THIS IS NOT HANDLED YET! * * Copyright (c) 2001 Axis Communications AB * * Author: Fredrik Hugosson * */#include <linux/module.h>#include <linux/init.h>#include <linux/parport.h>#include <linux/ioport.h>#include <linux/config.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/setup.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/segment.h>#include <asm/system.h>#include <asm/svinto.h>#undef DEBUG#ifdef DEBUG#define DPRINTK printk#elsestatic inline int DPRINTK(void *nothing, ...) {return 0;}#endif/* * Etrax100 DMAchannels: * Par0 out : DMA2 * Par0 in : DMA3 * Par1 out : DMA4 * Par1 in : DMA5 * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding * DMA and DMA irq *///#define CONFIG_PAR0_INT 1//#define CONFIG_PAR1_INT 1#define SETF(var, reg, field, val) \ var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)#define SETS(var, reg, field, val) \ var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)struct etrax100par_struct { /* parallell port control */ volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ volatile u32 *reg_config; /* R_PARx_CONFIG */ volatile u32 *reg_delay; /* R_PARx_DELAY */ /* DMA control */ int odma; unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ /* Non DMA interrupt stuff */ unsigned long int_irq; /* R_VECT_MASK_RD */ const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ const volatile u32 *irq_read; /* R_IRQ_READX */ volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ int portnr; /* ----- end of fields initialised in port_table[] below ----- */ struct parport *port; /* Shadow registers */ volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */};/* Always have the complete structs here, even if the port is not used! * (that way we can index this by the port number) */static struct etrax100par_struct port_table[] = { { R_PAR0_CTRL_DATA, R_PAR0_STATUS_DATA, R_PAR0_CONFIG, R_PAR0_DELAY, /* DMA interrupt stuff */ 2, 1U << 4, /* uses DMA 2 and 3 */ R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD, R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, /* Non DMA interrupt stuff */ IO_BITNR(R_VECT_MASK_RD, par0), R_IRQ_MASK0_RD, R_IRQ_MASK0_CLR, R_IRQ_READ0, R_IRQ_MASK0_SET, IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ 0 }, { R_PAR1_CTRL_DATA, R_PAR1_STATUS_DATA, R_PAR1_CONFIG, R_PAR1_DELAY, /* DMA interrupt stuff */ 4, 1U << 8, /* uses DMA 4 and 5 */ R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD, R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, /* Non DMA interrupt stuff */ IO_BITNR(R_VECT_MASK_RD, par1), R_IRQ_MASK1_RD, R_IRQ_MASK1_CLR, R_IRQ_READ1, R_IRQ_MASK1_SET, IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ 1 }};#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct))static voidparport_etrax_write_data(struct parport *p, unsigned char value){ struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); *info->reg_ctrl_data = info->reg_ctrl_data_shadow;}static unsigned charparport_etrax_read_data(struct parport *p){ unsigned char ret; struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); return ret;}static voidparport_etrax_write_control(struct parport *p, unsigned char control){ struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, (control & PARPORT_CONTROL_STROBE) > 0); SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, (control & PARPORT_CONTROL_AUTOFD) > 0); SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, (control & PARPORT_CONTROL_INIT) > 0); SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, (control & PARPORT_CONTROL_SELECT) > 0); *info->reg_ctrl_data = info->reg_ctrl_data_shadow;}static unsigned charparport_etrax_read_control( struct parport *p){ unsigned char ret = 0; struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) ret |= PARPORT_CONTROL_STROBE; if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) ret |= PARPORT_CONTROL_AUTOFD; if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) ret |= PARPORT_CONTROL_INIT; if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) ret |= PARPORT_CONTROL_SELECT; DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); return ret;}static unsigned charparport_etrax_frob_control(struct parport *p, unsigned char mask, unsigned char val){ unsigned char old; DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", p->portnum, mask, val); old = parport_etrax_read_control(p); parport_etrax_write_control(p, (old & ~mask) ^ val); return old;}static unsigned charparport_etrax_read_status(struct parport *p){ unsigned char ret = 0; struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) ret |= PARPORT_STATUS_ERROR; if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) ret |= PARPORT_STATUS_SELECT; if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) ret |= PARPORT_STATUS_PAPEROUT; if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) ret |= PARPORT_STATUS_ACK; if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) ret |= PARPORT_STATUS_BUSY; DPRINTK("* E100 PP %d: status register %04x\n", p->portnum, *info->reg_status_data); DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); return ret;}static voidparport_etrax_enable_irq(struct parport *p){ struct etrax100par_struct *info = (struct etrax100par_struct *)p->private_data; *info->irq_mask_set = info->irq_mask_tx; DPRINTK("* E100 PP %d: enable irq\n", p->portnum);}static voidparport_etrax_disable_irq(struct parport *p){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -