📄 pmacisa.c~
字号:
#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#include<linux/configfs.h>/*#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)# define MODVERSIONS#endif#ifdef MODVERSIONS# include<linux/modversions.h>#endif*/#include "pmacisa.h"#include<linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/proc_fs.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/ioport.h>/////////////////////////#defines for immutable pmac properties//////////////////////#define PMAC_HOST_BASE(x)(pmac_dev[x].host)#define PMAC_HOST_RANGE 0x10 /**total 16 ports & can change*/#define PMAC_STATUS(x)(pmac_dev[x].host + 2)#define PMAC_LO_INIT(x)(pmac_dev[x].host + 5)#define PMAC_HI_INIT(x)(pmac_dev[x].host + 6)#define PMAC_DATA(x)(pmac_dev[x].host + 7)#define PMAC_DPR_BASE(x)(pmac_dev[x].dpr)#define PMAC_DPR_VADD(x)(pmac_dev[x].dpr_vadd)#define PMAC_DPR_SIZE(x)(pmac_dev[x].size)#define PMAC_DPR_LENGTH 0x4000 /**can change */#define PMAC_RDY_TO_RCV(x)((inb_p(PMAC_STATUS(x)) & 2) == 2)#define PMAC_RDY_TO_SEND(x)((inb_p(PMAC_STATUS(x)) & 1) == 1)#define DPR_READ_STATUS(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_read_status)#define DPR_WRITE_STATUS(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_write_status)#define DPR_REG_CTRL_CHAR(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_ctrl_char)#define DRP_REG_NUM_CHAR(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_num_char)#define DPR_REG_READ(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_read)#define DPR_REG_WRITE(x)(PMAC_DPR_VADD(x) + pmac_dev[x].reg_write)#define DPR_NUM_CHARS(x)(readw(DRP_REG_NUM_CHAR(x)) - 1)#define DPR_READ_READY(x)(readw(DPR_READ_STATUS(x)) != 0)#define DPR_WRITE_READY(x)((readw(DPR_WRITE_STATUS(x)) & 0x0001) == 0)#define DPR_CLR_READ_READY(x)(writew(0, DPR_READ_STATUS(x)))#define DPR_CLR_WRITE_READY(x)(writew(0, DPR_WRITE_STATUS(x)))#define DPR_SET_WRITE_READY(x)(writew(1, DPR_WRITE_STATUS(x)))#define DPR_FLUSHED(x)((readw(DPR_READ_STATUS(x)) & 0x001F) == CTRL_X)#define DPR_ERROR(x)((readw(DPR_READ_STATUS(x)) & 0x8000) > 0)#define DPR_ERROR_CODE(x)(readw(DPR_READ_STATUS(x)) & 0x00FF)#define DPR_ACK(x)((readw(DPR_READ_STATUS(x)) & 0x000F) == ACK_CHR)#define DPR_CR(x)((readw(DPR_READ_STATUS(x)) & 0x000F) == CARRIAGE_RETURN)#define DPR_USER(x)((readw(DPR_READ_STATUS(x)) & 0x0300) != 0)MODULE_AUTHOR("chiefleo");MODULE_LICENSE("Dual BSD/GPL");///////////////////////////////GLOBAL VARIABLES/////////////////////////////////////static unsigned int major = 0; /* major device number, can be specified or used 0 for dynamic allocation*/module_param(major, int, S_IRUGO);/*MODULE_PARM(major, "i");*/static unsigned int host[PMAC_NO]={0x210}; /* pmac host port address, default is 0x210 *//*MODULE_PARM(host, "0-7i");*/static unsigned long dpr[PMAC_NO]={0x0}; /* pmac Dual Port Ram base address, default is 0xD0000 *//*MODULE_PARM(dpr, "0-7i");*/static unsigned long pmac_timeout_cnt = 2000; /* not implemented as desired... */static unsigned int delay_per_try = 5; /* micro seconds delay per try */static char driver_name[60]="Delta Tau Data Systems Inc. PMAC ISA";static int pmac_dev_no=0; //total successfully initialized devicesstatic struct _Pmac_Device pmac_dev[PMAC_NO];static struct proc_dir_entry* proc_pmac_dir;/////////////////////////////////////PORT functions//////////////////////////////// /*write_char_port() writes a single character to data port and if not ready waits *till time out. it returns the status of the communication */int write_char_port(unsigned int minor, char outchar){ unsigned long timeout=0; while(timeout++ < pmac_timeout_cnt){ if(PMAC_RDY_TO_RCV(minor)){ outb_p(outchar, PMAC_DATA(minor)); return COMM_OK; }else udelay(delay_per_try); } return COMM_TIMEOUT;} /*write_line_port() writes a null terminated string of size 256 to data port, *and writes the carriage return 0x0D(13) to end pmac command. it sets the *status and returns the number of characters written to the port */int write_line_port(unsigned int minor, char *buffer, int *status){ unsigned int nc=0; int result=COMM_OK; while(buffer[nc]!=NULL_CHR && nc<255 && result==COMM_OK) result=write_char_port(minor, buffer[nc++]); if(result==COMM_OK) result=write_char_port(minor, CARRIAGE_RETURN); *status=result; return nc;} /*read_line_port() reads data from data port. it does not send the ACK character back. *it checks for watchdog or junk, terminates the buffer with null and sets the status *accordingly and returns the number of character read */int read_line_port(unsigned int minor, char *buffer, int *status){ unsigned long timeout=0; int nc=0; while(timeout<pmac_timeout_cnt && nc<256) { if(!PMAC_RDY_TO_SEND(minor)) { udelay(delay_per_try); timeout++; continue; } buffer[nc] = inb_p(PMAC_DATA(minor)); timeout=0; if(buffer[nc] == ACK_CHR) { *status = COMM_EOT; break; } else if(buffer[nc] == CARRIAGE_RETURN) { nc++; *status=COMM_OK; break; } else if(buffer[nc] > 0x7E) { *status=COMM_ERROR; break; } else if(buffer[nc] == CTRL_G) *status=COMM_ERROR; else nc++; if(*status==COMM_ERROR && !PMAC_RDY_TO_SEND(minor)) break; } if (timeout>=pmac_timeout_cnt) *status=COMM_TIMEOUT; buffer[nc] = NULL_CHR;// printk (KERN_NOTICE "pmac isa: Card sent following string %s at port 0x%X\n", buffer, PMAC_HOST_BASE(minor)); return nc;} /*flush_port() clears out any garbage in pmac command buffer by writing Ctrl-X and *then reads few characters back to clear out data buffer */int flush_port(unsigned int minor){ int i=0; unsigned int temp; write_char_port(minor, CTRL_X); while(i++<pmac_timeout_cnt) { if(!PMAC_RDY_TO_SEND(minor)) { udelay(delay_per_try); continue; } temp = inb_p(PMAC_DATA(minor)); if(temp == CTRL_X) {// printk (KERN_NOTICE "pmac isa: flush_port successful 0x%X at port 0x%X\n", temp, PMAC_HOST_BASE(minor)); return 0; } else if(temp == 0xFF) { printk (KERN_NOTICE "pmac isa: flush_port returned 0x%X at port 0x%X\n", temp, PMAC_HOST_BASE(minor)); return -ENODEV; } else { printk (KERN_NOTICE "pmac isa: flush_port returned garbage 0x%X at port 0x%X\n", temp, PMAC_HOST_BASE(minor)); return -ENODEV; } } printk (KERN_NOTICE "pmac isa: flush_port command timed out with %d tries at port 0x%X\n", i, PMAC_HOST_BASE(minor)); return -ENODEV;} /*get_ctrl_resp() sends requested ctrl character between 1-26 to pmac. if request is known *not to return any characters it sets the EOT status bit then exits. if request is know to *return 1 line of data then function grabs the data and sets EOT. if n lines are returned *function does not grab data and nor does set EOT */int get_ctrl_resp(unsigned int minor, char *buffer, int *status){ int result=0; *status=COMM_OK; if(!buffer[0]==CTRL_I) flush_port(minor); write_char_port(minor, buffer[0]); switch(buffer[0]){ case CTRL_B: case CTRL_C: case CTRL_F: case CTRL_G: case CTRL_P: case CTRL_T: case CTRL_V: case CTRL_Y: case CTRL_X: result=read_line_port(minor, buffer, status); break; case CTRL_E: case CTRL_I: buffer[0]=NULL_CHR; break; default: buffer[0]=NULL_CHR; *status=COMM_EOT; } return result;}/////////////////////////////////////DPRAM functions//////////////////////////////////int write_char_mem(unsigned int minor, char outchar){ unsigned long timeout=0; if(!pmac_dev[minor].has_memory) return -EPERM; while(timeout++ < pmac_timeout_cnt){ if(DPR_WRITE_READY(minor)){ if(CTRL_A <= outchar && outchar <= CTRL_Z){ writeb(outchar, DPR_REG_CTRL_CHAR(minor)); DPR_SET_WRITE_READY(minor); }else{ writeb(outchar, DPR_REG_WRITE(minor)); writeb(NULL_CHR, DPR_REG_WRITE(minor) + 1); DPR_SET_WRITE_READY(minor); } return COMM_OK; }else udelay(delay_per_try); } return COMM_TIMEOUT;}int flush_mem(unsigned int minor){ int i=0, status; if(!pmac_dev[minor].has_memory) return -EPERM; write_char_mem(minor, CTRL_X); while(i++<pmac_timeout_cnt){ if(DPR_READ_READY(minor)){ if(DPR_FLUSHED(minor)) status = COMM_OK; else status = COMM_ERROR; DPR_CLR_READ_READY(minor); }else udelay(delay_per_try); } status = COMM_TIMEOUT; return status;} /*write_line_mem() write string to dpram ascii port, returns no of characters written to dpram *or a -ve no if there is no DPRAM */int write_line_mem(unsigned int minor, char *buffer, int *status){ int nc=0; unsigned long timeout=0; if(!pmac_dev[minor].has_memory) return -EPERM; while(buffer[nc] != NULL_CHR) nc++; if(nc > MAX_DPR_BUFFER){ *status = COMM_ERROR; return -EPERM; } while(timeout++ < pmac_timeout_cnt){ if(DPR_WRITE_READY(minor)){ memcpy_toio(DPR_REG_WRITE(minor), buffer, nc + 1); DPR_SET_WRITE_READY(minor); *status = COMM_OK; return nc; }else udelay(delay_per_try); } *status = COMM_TIMEOUT; return 0;} /*read_line_mem() reads a string from DPR ascii port */int read_line_mem(unsigned int minor, char *buffer, int *status){ unsigned long timeout = 0; unsigned int retval=0; if(!pmac_dev[minor].has_memory) return -EPERM; while(timeout++ < pmac_timeout_cnt){ if(DPR_READ_READY(minor)){ if(DPR_ERROR(minor)){ retval = DPR_ERROR_CODE(minor); *status = COMM_ERROR; DPR_CLR_READ_READY(minor); return retval; } retval = DPR_NUM_CHARS(minor); if(retval > 0){ if(!(retval < MAX_COMM_BUFFER)) retval = MAX_COMM_BUFFER - 1; memcpy_fromio(buffer, DPR_REG_READ(minor), retval); } if(DPR_CR(minor)){ buffer[retval] = CARRIAGE_RETURN; retval++; }else if(DPR_ACK(minor)){ *status = COMM_EOT; }else if(DPR_USER(minor)) *status = COMM_UNSOLICITED; DPR_CLR_READ_READY(minor); buffer[retval] = NULL_CHR; return retval; }else udelay(delay_per_try); } *status = COMM_TIMEOUT; return 0;} /*set_mem() writes a string to any offset on dpram */int set_mem(unsigned int minor, char *buffer, int *status, unsigned long offset, unsigned int count){ if(!pmac_dev[minor].has_memory) return -EPERM; if(count > 0 && count < PMAC_DPR_SIZE(minor)) if((PMAC_DPR_VADD(minor) + offset + (unsigned long)count) > (PMAC_DPR_VADD(minor) + PMAC_DPR_SIZE(minor))){ *status = COMM_ERROR; return -ENXIO; } memcpy_toio(PMAC_DPR_VADD(minor) + offset, buffer, count); *status = COMM_OK; return count;} /*get_mem() reads a string from any offset on dpram */int get_mem(unsigned int minor, char *buffer, int *status, unsigned long offset, unsigned int count){ if(!pmac_dev[minor].has_memory) return -EPERM; if(count > 0 && count < PMAC_DPR_SIZE(minor)) if((PMAC_DPR_VADD(minor) + offset + (unsigned long)count) > (PMAC_DPR_VADD(minor) + PMAC_DPR_SIZE(minor))){ *status = COMM_ERROR; return -ENXIO; } memcpy_fromio(buffer, PMAC_DPR_VADD(minor) + offset, count); *status = COMM_OK; return count;} /*get_ctrl_resp_mem() sends requested control character to PMAC... */int get_ctrl_resp_mem(unsigned int minor, char *buffer, int *status){ int result=0; *status = COMM_OK; if(!pmac_dev[minor].has_memory) return -EPERM; if(!buffer[0]==CTRL_I) result = flush_mem(minor); if(buffer[0]==CTRL_X) /** already flushed in last statement*/ return result; write_char_mem(minor, buffer[0]); switch(buffer[0]){ case CTRL_B: case CTRL_C: case CTRL_F: case CTRL_G: case CTRL_P: case CTRL_T: case CTRL_V: case CTRL_Y: result=read_line_mem(minor, buffer, status); if(*status == COMM_OK) *status = COMM_EOT; break; case CTRL_E: case CTRL_I: buffer[0]=NULL_CHR; *status = COMM_OK; break; default: buffer[0]=NULL_CHR; *status=COMM_EOT; } return result;}/////////////////////////////////////General functions//////////////////////////////// /*get_dpr_base() sets the base address of the PMAC's dpram */unsigned long get_dpr_base(unsigned int minor){ //...will implement later... return 0;} /*set_dpr_base() sets the base address of the PMAC's dpram, will imporve in future... */int set_dpr_base(unsigned int minor){ unsigned int d1, d2; char str[256]; int status; unsigned long base = PMAC_DPR_BASE(minor); struct _Pmac_Device *device = &pmac_dev[minor]; d1 = (base & 0xF0000) >> 16; d2 = ((base & 0x0F000) >> 8) + 0x5; if(device->type > PT_PMAC){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -