📄 comx-hw-comx.c
字号:
loopcount=0; while(loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1) { udelay(100); } if ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) { printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n", dev->name, COMX_readw(dev, OFF_A_L2_LINKUP)); retval=-EAGAIN; goto out; } ch->init_status |= FW_LOADED; retval=0;out: outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr); outb_p(HICOMX_DATA_MEM, dev->base_addr + 1); if(saved) { ((struct comx_channel *)saved->priv)->HW_board_on(saved); } memory_used[mempos]=saved; restore_flags(flags); return retval;}static struct net_device *comx_twin_check(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct proc_dir_entry *procfile = ch->procdir->parent->subdir; struct comx_privdata *hw = ch->HW_privdata; struct net_device *twin; struct comx_channel *ch_twin; struct comx_privdata *hw_twin; for ( ; procfile ; procfile = procfile->next) { if(!S_ISDIR(procfile->mode)) { continue; } twin=procfile->data; ch_twin=twin->priv; hw_twin=ch_twin->HW_privdata; if (twin != dev && dev->irq && dev->base_addr && dev->mem_start && dev->irq == twin->irq && dev->base_addr == twin->base_addr && dev->mem_start == twin->mem_start && hw->channel == (1 - hw_twin->channel) && ch->hardware == ch_twin->hardware) { return twin; } } return NULL;}static int comxhw_write_proc(struct file *file, const char *buffer, u_long count, void *data){ struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = entry->parent->data; struct comx_channel *ch = dev->priv; struct comx_privdata *hw = ch->HW_privdata; char *page; if(ch->init_status & HW_OPEN) { return -EAGAIN; } if (strcmp(FILENAME_FIRMWARE, entry->name) != 0) { if (!(page = (char *)__get_free_page(GFP_KERNEL))) { return -ENOMEM; } if(copy_from_user(page, buffer, count = (min_t(int, count, PAGE_SIZE)))) { count = -EFAULT; goto out; } if (page[count-1] == '\n') page[count-1] = '\0'; else if (count < PAGE_SIZE) page[count] = '\0'; else if (page[count]) { count = -EINVAL; goto out; } page[count]=0; /* Null terminate */ } else { byte *tmp; if (!hw->firmware) { if ((hw->firmware = kmalloc(sizeof(struct comx_firmware), GFP_KERNEL)) == NULL) { return -ENOMEM; } hw->firmware->len = 0; hw->firmware->data = NULL; } if ((tmp = kmalloc(count + file->f_pos, GFP_KERNEL)) == NULL) { return -ENOMEM; } /* Ha nem 0 a fpos, akkor meglevo file-t irunk. Gyenge trukk. */ if (hw->firmware && hw->firmware->len && file->f_pos && hw->firmware->len < count + file->f_pos) { memcpy(tmp, hw->firmware->data, hw->firmware->len); } if (hw->firmware->data) { kfree(hw->firmware->data); } copy_from_user(tmp + file->f_pos, buffer, count); hw->firmware->len = entry->size = file->f_pos + count; hw->firmware->data = tmp; file->f_pos += count; return count; } if (strcmp(entry->name, FILENAME_CHANNEL) == 0) { hw->channel = simple_strtoul(page, NULL, 0); if (hw->channel >= MAX_CHANNELNO) { printk(KERN_ERR "Invalid channel number\n"); hw->channel = 0; } if ((ch->twin = comx_twin_check(dev)) != NULL) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = dev; } } else if (strcmp(entry->name, FILENAME_IRQ) == 0) { dev->irq = simple_strtoul(page, NULL, 0); if (dev->irq == 2) { dev->irq = 9; } if (dev->irq < 3 || dev->irq > 15) { printk(KERN_ERR "comxhw: Invalid irq number\n"); dev->irq = 0; } if ((ch->twin = comx_twin_check(dev)) != NULL) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = dev; } } else if (strcmp(entry->name, FILENAME_IO) == 0) { dev->base_addr = simple_strtoul(page, NULL, 0); if ((dev->base_addr & 3) != 0 || dev->base_addr < 0x300 || dev->base_addr > 0x3fc) { printk(KERN_ERR "Invalid io value\n"); dev->base_addr = 0; } if ((ch->twin = comx_twin_check(dev)) != NULL) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = dev; } } else if (strcmp(entry->name, FILENAME_MEMADDR) == 0) { dev->mem_start = simple_strtoul(page, NULL, 0); if (dev->mem_start <= 0xf000 && dev->mem_start >= 0xa000) { dev->mem_start *= 16; } if ((dev->mem_start & 0xfff) != 0 || dev->mem_start < COMX_MEM_MIN || dev->mem_start + hw->memory_size > COMX_MEM_MAX) { printk(KERN_ERR "Invalid memory page\n"); dev->mem_start = 0; } dev->mem_end = dev->mem_start + hw->memory_size; if ((ch->twin = comx_twin_check(dev)) != NULL) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = dev; } } else if (strcmp(entry->name, FILENAME_CLOCK) == 0) { if (strncmp("ext", page, 3) == 0) { hw->clock = 0; } else { int kbps; kbps = simple_strtoul(page, NULL, 0); hw->clock = kbps ? COMX_CLOCK_CONST/kbps : 0; } }out: free_page((unsigned long)page); return count;}static int comxhw_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; struct comx_channel *ch = dev->priv; struct comx_privdata *hw = ch->HW_privdata; int len = 0; if (strcmp(file->name, FILENAME_IO) == 0) { len = sprintf(page, "0x%03x\n", (unsigned int)dev->base_addr); } else if (strcmp(file->name, FILENAME_IRQ) == 0) { len = sprintf(page, "0x%02x\n", dev->irq == 9 ? 2 : dev->irq); } else if (strcmp(file->name, FILENAME_CHANNEL) == 0) { len = sprintf(page, "%01d\n", hw->channel); } else if (strcmp(file->name, FILENAME_MEMADDR) == 0) { len = sprintf(page, "0x%05x\n", (unsigned int)dev->mem_start); } else if (strcmp(file->name, FILENAME_TWIN) == 0) { len = sprintf(page, "%s\n", ch->twin ? ch->twin->name : "none"); } else if (strcmp(file->name, FILENAME_CLOCK) == 0) { if (hw->clock) { len = sprintf(page, "%-8d\n", COMX_CLOCK_CONST/hw->clock); } else { len = sprintf(page, "external\n"); } } else if (strcmp(file->name, FILENAME_FIRMWARE) == 0) { len = min_t(int, FILE_PAGESIZE, min_t(int, count, hw->firmware ? (hw->firmware->len - off) : 0)); if (len < 0) { len = 0; } *start = hw->firmware ? (hw->firmware->data + off) : NULL; if (off + len >= (hw->firmware ? hw->firmware->len : 0) || len == 0) { *eof = 1; } return len; } if (off >= len) { *eof = 1; return 0; } *start = page + off; if (count >= len - off) { *eof = 1; } return min_t(int, count, len - off);}/* Called on echo comx >boardtype */static int COMX_init(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct comx_privdata *hw; struct proc_dir_entry *new_file; if ((ch->HW_privdata = kmalloc(sizeof(struct comx_privdata), GFP_KERNEL)) == NULL) { return -ENOMEM; } memset(hw = ch->HW_privdata, 0, sizeof(struct comx_privdata)); if (ch->hardware == &comx_hw || ch->hardware == &cmx_hw) { hw->memory_size = COMX_MEMORY_SIZE; hw->io_extent = COMX_IO_EXTENT; dev->base_addr = COMX_DEFAULT_IO; dev->irq = COMX_DEFAULT_IRQ; dev->mem_start = COMX_DEFAULT_MEMADDR; dev->mem_end = COMX_DEFAULT_MEMADDR + COMX_MEMORY_SIZE; } else if (ch->hardware == &hicomx_hw) { hw->memory_size = HICOMX_MEMORY_SIZE; hw->io_extent = HICOMX_IO_EXTENT; dev->base_addr = HICOMX_DEFAULT_IO; dev->irq = HICOMX_DEFAULT_IRQ; dev->mem_start = HICOMX_DEFAULT_MEMADDR; dev->mem_end = HICOMX_DEFAULT_MEMADDR + HICOMX_MEMORY_SIZE; } else { printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__); } if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_HW_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->size = 6; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_io; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->size = 5; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_irq; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->size = 2; // Ezt tudjuk new_file->nlink = 1; if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) { if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_channel; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->size = 9; new_file->nlink = 1; } if ((new_file = create_proc_entry(FILENAME_MEMADDR, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_clock; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->size = 8; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, ch->procdir)) == NULL) { goto cleanup_filename_memaddr; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = NULL; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_FIRMWARE, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_twin; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; new_file->write_proc = &comxhw_write_proc; new_file->nlink = 1; if (ch->hardware == &comx_hw) { ch->HW_board_on = COMX_board_on; ch->HW_board_off = COMX_board_off; ch->HW_load_board = COMX_load_board; } else if (ch->hardware == &cmx_hw) { ch->HW_board_on = COMX_board_on; ch->HW_board_off = COMX_board_off; ch->HW_load_board = CMX_load_board; ch->HW_set_clock = COMX_set_clock; } else if (ch->hardware == &hicomx_hw) { ch->HW_board_on = HICOMX_board_on; ch->HW_board_off = HICOMX_board_off; ch->HW_load_board = HICOMX_load_board; ch->HW_set_clock = COMX_set_clock; } else { printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__); } ch->HW_access_board = COMX_access_board; ch->HW_release_board = COMX_release_board; ch->HW_txe = COMX_txe; ch->HW_open = COMX_open; ch->HW_close = COMX_close; ch->HW_send_packet = COMX_send_packet; ch->HW_statistics = COMX_statistics; if ((ch->twin = comx_twin_check(dev)) != NULL) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = dev; } MOD_INC_USE_COUNT; return 0;cleanup_filename_twin: remove_proc_entry(FILENAME_TWIN, ch->procdir);cleanup_filename_memaddr: remove_proc_entry(FILENAME_MEMADDR, ch->procdir);cleanup_filename_clock: if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) remove_proc_entry(FILENAME_CLOCK, ch->procdir);cleanup_filename_channel: remove_proc_entry(FILENAME_CHANNEL, ch->procdir);cleanup_filename_irq: remove_proc_entry(FILENAME_IRQ, ch->procdir);cleanup_filename_io: remove_proc_entry(FILENAME_IO, ch->procdir);cleanup_HW_privdata: kfree(ch->HW_privdata); return -EIO;}/* Called on echo valami >boardtype */static int COMX_exit(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct comx_privdata *hw = ch->HW_privdata; if (hw->firmware) { if (hw->firmware->data) kfree(hw->firmware->data); kfree(hw->firmware); } if (ch->twin) { struct comx_channel *twin_ch = ch->twin->priv; twin_ch->twin = NULL; } kfree(ch->HW_privdata); remove_proc_entry(FILENAME_IO, ch->procdir); remove_proc_entry(FILENAME_IRQ, ch->procdir); remove_proc_entry(FILENAME_CHANNEL, ch->procdir); remove_proc_entry(FILENAME_MEMADDR, ch->procdir); remove_proc_entry(FILENAME_FIRMWARE, ch->procdir); remove_proc_entry(FILENAME_TWIN, ch->procdir); if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) { remove_proc_entry(FILENAME_CLOCK, ch->procdir); } MOD_DEC_USE_COUNT; return 0;}static int COMX_dump(struct net_device *dev){ printk(KERN_INFO "%s: COMX_dump called, why ?\n", dev->name); return 0;}static struct comx_hardware comx_hw = { "comx", VERSION, COMX_init, COMX_exit, COMX_dump, NULL};static struct comx_hardware cmx_hw = { "cmx", VERSION, COMX_init, COMX_exit, COMX_dump, NULL};static struct comx_hardware hicomx_hw = { "hicomx", VERSION, COMX_init, COMX_exit, COMX_dump, NULL};#ifdef MODULE#define comx_hw_comx_init init_module#endifint __init comx_hw_comx_init(void){ comx_register_hardware(&comx_hw); comx_register_hardware(&cmx_hw); comx_register_hardware(&hicomx_hw); memset(memory_used, 0, sizeof(memory_used)); return 0;}#ifdef MODULEvoid cleanup_module(void){ comx_unregister_hardware("comx"); comx_unregister_hardware("cmx"); comx_unregister_hardware("hicomx");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -