📄 pmacisa.c~
字号:
sprintf(str, "wx$70009,$%X,$%X",d1,d2); write_line_port(minor, str, &status); read_line_port(minor, str, &status); sprintf(str, "I93=$%X I94=$%X",d1,d2); write_line_port(minor, str, &status); read_line_port(minor, str, &status); }else{ sprintf(str, "wx$E009,$%X,$%X",d1,d2); write_line_port(minor, str, &status); read_line_port(minor, str, &status); sprintf(str, "wx$786,$%X,$%X",d1,d2); write_line_port(minor, str, &status); read_line_port(minor, str, &status); } return 0;} /*dpr_initialize() intializes the dpr register variables in _Pmac_Device structure *depending on the pmac device type */int dpr_initialize(unsigned int minor){ struct _Pmac_Device *device = &pmac_dev[minor]; if(device->type > PT_PMAC){ /** Is it Turbo! */ device->reg_write_status = 0x0E9C; device->reg_read_status = 0x0F40; device->reg_ctrl_char = 0x0E9E; device->reg_num_char = 0x0F42; device->reg_write = 0x0EA0; device->reg_read = 0xF44; }else{ device->reg_write_status = 0x062C; device->reg_read_status = 0x06D0; device->reg_ctrl_char = 0x062E; device->reg_num_char = 0x06D2; device->reg_write = 0x0630; device->reg_read = 0x06D4; } return 0;} /*get_pmac_param() is used only in pmac_read_procmem to fill proc entries *and in pmac_intialize() to find the type of the pmac */int get_pmac_param(unsigned int minor, char *buffer, char *pmac_cmd){ int status, len=0; int result = 0; char cdummy[256]; flush_port(minor); write_line_port(minor, pmac_cmd, &status); if (status == COMM_OK) { len=read_line_port(minor, buffer, &status); if (status == COMM_EOT) { buffer[--len]=NULL_CHR; result = 1; } else if(status == COMM_OK) // get the ACK as well { read_line_port(minor, cdummy, &status); if(status == COMM_EOT) result = 1; } result = 0; } return result;} /*pmac_initialize() initializes the pmac at the very first communication */int pmac_initialize(unsigned int minor){ int nt = 0, result = -1; char type[20]; outb_p(0, PMAC_LO_INIT(minor)); outb_p(0, PMAC_HI_INIT(minor)); while(nt++ < pmac_timeout_cnt) { udelay(delay_per_try); } result=flush_port(minor); result=flush_port(minor); if (result < 0) { printk (KERN_NOTICE "pmac isa: pmac_initialize failure at port 0x%X with result %d\n", PMAC_HOST_BASE(minor),result); return result; // failure } pmac_dev[minor].type = PT_UNKNOWN; get_pmac_param(minor, type, "type\0"); if(strstr(type, "PMAC1")) pmac_dev[minor].type = PT_PMAC1; else if(strstr(type, "PMAC2")) pmac_dev[minor].type = PT_PMAC2; else if(strstr(type, "PMACU")) pmac_dev[minor].type = PT_PMACUL; else if(strstr(type, "TURBO1")) pmac_dev[minor].type = PT_PMAC1T; else if(strstr(type, "TURBO2")) pmac_dev[minor].type = PT_PMAC2T; else if(strstr(type, "TURBOU")) pmac_dev[minor].type = PT_PMACUT; printk (KERN_NOTICE "pmac isa: pmac_initialize gets pamctype %d at port 0x%X\n", pmac_dev[minor].type, PMAC_HOST_BASE(minor)); if(pmac_dev[minor].type == PT_UNKNOWN) return 0; else // success return 1;} /*pmac_find_hardware() checks if card is in slot. if not the response will *be an infinite array of 0xFF */int pmac_find_hardware (unsigned int minor){ int nt = 0, result = -1; outb_p(0,PMAC_LO_INIT(minor)); outb_p(0,PMAC_HI_INIT(minor)); outb_p(0,PMAC_STATUS(minor)); while(nt++ < pmac_timeout_cnt) { udelay(delay_per_try); } result = flush_port(minor); result = flush_port(minor); if (result < 0) { printk (KERN_NOTICE "pmac isa: pmac_find_hardware failure at port 0x%X with result %d\n", PMAC_HOST_BASE(minor),result); return result; } return 0;} /*pmac_read_procmem() fills up the proc entry /proc/pmacisa */int pmac_read_procmem(char *buff, char **start, off_t offset, int count, int *eof, void *data){ unsigned int device, len=0; char type[20], version[15], date[15]; len += sprintf(buff+len, "%s\n", driver_name); len += sprintf(buff+len, "Total ISA Devices %d\n", pmac_dev_no); device=0; for(device=0; device<pmac_dev_no; device++){ len += sprintf(buff+len, "Device %d\n", device); len += sprintf(buff+len, "\tPort 0x%X, DPR Base 0x%lX\n", pmac_dev[device].host, pmac_dev[device].dpr); get_pmac_param(device, type, "type\0"); get_pmac_param(device, version, "version\0"); get_pmac_param(device, date, "date\0"); len += sprintf(buff+len, "\tType %s, Version %s, Date %s:\n", type, version, date); } return len;}///////////////////////////system call implementation for pmac////////////////////////////////int pmac_open (struct inode *inode, struct file *filp){ unsigned int minor = MINOR(inode->i_rdev); if(minor >= pmac_dev_no) return -ENODEV; if(!(pmac_dev[minor].has_region)) return -ENODEV; /*MOD_INC_USE_COUNT;*/ return 0;}int pmac_release (struct inode *inode, struct file *filp){ /*MOD_DEC_USE_COUNT;*/ return 0;}int pmac_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0, result = 0; struct _Device_Ext *pdx, *parg; unsigned int minor = MINOR(inode->i_rdev); if (_IOC_TYPE(cmd) != IOCTL_MOTION_BASE) return -ENOTTY; // extract the type and number bitfields, and don't decode wrong cmds if (_IOC_NR(cmd) > IOCTL_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) //The concept of "read" and "write" is reversed in following err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; parg = (struct _Device_Ext *) arg; pdx = &pmac_dev[minor].ext; switch(cmd){ case IOCTL_MOTION_INIT: outb_p(0, PMAC_LO_INIT(minor)); outb_p(0, PMAC_HI_INIT(minor)); result = 0; break; case IOCTL_MOTION_FLUSH_PORT: result = flush_port(minor); break; case IOCTL_MOTION_PORT_READREADY: //return 0 if ready to read else return -ve value if (!(PMAC_RDY_TO_SEND(minor))) return -EBUSY; result = 0; break; case IOCTL_MOTION_READLN_PORT: result = read_line_port(minor, pdx->buffer, &pdx->status); if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; break; case IOCTL_MOTION_WRITELN_PORT: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = write_line_port(minor, pdx->buffer, &pdx->status); break; case IOCTL_MOTION_WRITECHAR_PORT: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = write_char_port(minor, pdx->buffer[0]); //character to be written to port is at buffer[0] break; case IOCTL_WRITECHAR_PORT: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; outb_p(PMAC_HOST_BASE(minor) + pdx->buffer[0], pdx->buffer[1]); //offset is at buffer[0] and character at buffer[1] result = 0; break; case IOCTL_READCHAR_PORT: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; pdx->buffer[1]=inb_p(PMAC_HOST_BASE(minor) + pdx->buffer[0]); //data read from offset buffer[0] is stored in buffer[1] if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; result = 0; break; case IOCTL_MOTION_CTRLRESP_PORT: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = get_ctrl_resp(minor, pdx->buffer, &pdx->status); if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; break; case IOCTL_MOTION_FLUSH_MEM: result = flush_mem(minor); break; case IOCTL_MOTION_MEM_READREADY: if (!(DPR_READ_READY(minor))) return -EBUSY; result = 0; break; case IOCTL_MOTION_READLN_MEM: result = read_line_mem(minor, pdx->buffer, &pdx->status); if(pdx->status == COMM_ERROR){ pdx->err_code = result; result=0; } if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; break; case IOCTL_MOTION_WRITELN_MEM: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = write_line_mem(minor, pdx->buffer, &pdx->status); break; case IOCTL_MOTION_WRITECHAR_MEM: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = write_char_mem(minor, pdx->buffer[0]); //character to be written to port is at buffer[0] break; case IOCTL_MOTION_WRITECTRL_MEM: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = write_char_mem(minor, pdx->buffer[0]); //character to be written to port is at buffer[0] break; case IOCTL_MOTION_GET_MEM: result = get_mem(minor, pdx->buffer, &pdx->status, pdx->dpr_offset, pdx->dpr_count); if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; break; case IOCTL_MOTION_SET_MEM: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = set_mem(minor, pdx->buffer, &pdx->status, pdx->dpr_offset, pdx->dpr_count); break; case IOCTL_MOTION_CTRLRESP_MEM: if (copy_from_user(pdx, parg, sizeof (struct _Device_Ext))) return -EFAULT; result = get_ctrl_resp_mem(minor, pdx->buffer, &pdx->status); if(copy_to_user(parg, pdx, sizeof (struct _Device_Ext))) return -EFAULT; break; case IOCTL_MOTION_DPRAM: result = pmac_dev[minor].has_memory; break; } return result;}/**ssize_t pmac_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) { unsigned char *kbuf=kmalloc(count, GFP_KERNEL); unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev); if(!pmac_dev[minor].has_memory) return -EPERM; if (!kbuf) return -ENOMEM; if(count > 0 && count < PMAC_DPR_SIZE(minor)) if((*f_pos + (unsigned long)count) > (PMAC_DPR_VADD(minor) + PMAC_DPR_SIZE(minor))){ return -ENXIO; } if (copy_from_user(kbuf, buf, count)) return -EFAULT; memcpy_toio(f_pos, kbuf, count); kfree(kbuf); return count;}ssize_t pmac_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { unsigned char *kbuf=kmalloc(count, GFP_KERNEL); unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev); if (!kbuf) return -ENOMEM; if(!pmac_dev[minor].has_memory) return -EPERM; if(count > 0 && count < PMAC_DPR_SIZE(minor)) if((*f_pos + (unsigned long)count) > (PMAC_DPR_VADD(minor) + PMAC_DPR_SIZE(minor))){ return -ENXIO; } memcpy_fromio(kbuf, f_pos, count); if ( (count > 0) && copy_to_user(buf, kbuf, count)) retval = -EFAULT; kfree(kbuf); return count;}**/////////////////////////////////Declaration of File Operations///////////////////////////////struct file_operations pmac_fops = { .owner = THIS_MODULE,// read: pmac_read,// write: pmac_write, .ioctl = pmac_ioctl, .open = pmac_open, .release = pmac_release,};////////////////////////module init and clean up///////////////////////////////////////////// /*Release IO Region, Memory Region and major node number */void pmac_cleanup_module(void){ unsigned int minor; for(minor=0; minor<PMAC_NO; minor++){ if(host[minor]==0) break; if(pmac_dev[minor].has_region){ release_region (PMAC_HOST_BASE(minor), PMAC_HOST_RANGE); } if(pmac_dev[minor].has_region && pmac_dev[minor].has_memory){ release_mem_region(PMAC_DPR_BASE(minor), PMAC_DPR_SIZE(minor)); iounmap(pmac_dev[minor].dpr_vadd); } } if(proc_pmac_dir) remove_proc_entry("pmacisa", proc_pmac_dir); unregister_chrdev (major, "pmacisa"); printk (KERN_NOTICE "pmac isa: Driver Unloaded successfully\n");} /*all intializing stuff... */int pmac_init_module (void) { int result; unsigned int minor; struct proc_dir_entry* temp; /*EXPORT_NO_SYMBOLS;*/ if ((result=register_chrdev (major, "pmacisa", &pmac_fops)) < 0) { // Attempt to register the major node number of the PMAC. printk (KERN_WARNING "pmac isa: Can't get major number %d\n", major); return result; } if(major==0) major=result; for(temp=proc_root_driver->subdir; temp; temp=temp->next) if (strstr(temp->name, "pmac")) proc_pmac_dir = temp; if(!proc_pmac_dir) proc_pmac_dir = proc_mkdir("pmac", proc_root_driver); if(proc_pmac_dir) create_proc_read_entry("pmacisa", 0, proc_pmac_dir, pmac_read_procmem, NULL); for(minor=0; minor<PMAC_NO; minor++){ if(host[minor]==0) break; pmac_dev[minor].host = host[minor]; pmac_dev[minor].range = PMAC_HOST_RANGE; pmac_dev[minor].dpr = dpr[minor]; pmac_dev[minor].size = PMAC_DPR_LENGTH; if (pmac_find_hardware(minor)<0) { printk(KERN_WARNING "pmac isa: pmac_find_hardware failure at port 0x%X\n", PMAC_HOST_BASE(minor)); continue; } if(check_region(PMAC_HOST_BASE(minor), PMAC_HOST_RANGE)<0){ // Check IO Region for PMAC communication. printk(KERN_WARNING "pmac isa: Can't allocate port 0x%X\n", PMAC_HOST_BASE(minor)); pmac_dev[minor].has_region=0; continue; }else{ request_region (PMAC_HOST_BASE(minor), PMAC_HOST_RANGE, driver_name); //Request io and memory region pmac_dev[minor].has_region=1; } if(pmac_initialize (minor) > 0) { pmac_dev_no++; printk(KERN_WARNING "pmac isa: pmac_initialize Device number %d successful at port 0x%X\n", pmac_dev_no, PMAC_HOST_BASE(minor)); } if(pmac_dev[minor].dpr!=0 && pmac_dev[minor].has_region){ if (check_mem_region(PMAC_DPR_BASE(minor), PMAC_DPR_SIZE(minor))<0){ // Check IO Memory for PMAC Dual Port Ram Communication. printk(KERN_WARNING "pmac isa: Can't allocate memory for dual port ram at 0x%lX\n", PMAC_DPR_BASE(minor)); pmac_dev[minor].has_memory=0; continue; }else{ set_dpr_base(minor); // set pmac dpr registers to required address request_mem_region(PMAC_DPR_BASE(minor), PMAC_DPR_SIZE(minor), driver_name); pmac_dev[minor].dpr_vadd = ioremap(PMAC_DPR_BASE(minor), PMAC_DPR_SIZE(minor)); pmac_dev[minor].has_memory=1; dpr_initialize(minor); // initialize the dpr register variables in pmac_dev } }else{ pmac_dev[minor].has_memory=0; pmac_dev[minor].size=0; //set size to zero if no dpr } } printk(KERN_NOTICE "pmac isa: Driver successfully loaded, Total Devices: %d\n", pmac_dev_no); return 0;}module_init(pmac_init_module);module_exit(pmac_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -