static int comxlapb_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 lapb_parms_struct parms;
	unsigned long parm;
	char *page;

	if (lapb_getparms(dev->priv, &parms)) {
		return -ENODEV;
	}

	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
		return -ENOMEM;
	}

	copy_from_user(page, buffer, count);
	if (*(page + count - 1) == '\n') {
		*(page + count - 1) = 0;
	}

	if (strcmp(entry->name, FILENAME_T1) == 0) {
		parm=simple_strtoul(page,NULL,10);
		if (parm > 0 && parm < 100) {
			parms.t1=parm;
			lapb_setparms(dev->priv, &parms);
		}
	} else if (strcmp(entry->name, FILENAME_T2) == 0) {
		parm=simple_strtoul(page, NULL, 10);
		if (parm > 0 && parm < 100) {
			parms.t2=parm;
			lapb_setparms(dev->priv, &parms);
		}
	} else if (strcmp(entry->name, FILENAME_N2) == 0) {
		parm=simple_strtoul(page, NULL, 10);
		if (parm > 0 && parm < 100) {
			parms.n2=parm;
			lapb_setparms(dev->priv, &parms);
		}
	} else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
		parms.window = simple_strtoul(page, NULL, 10);
		lapb_setparms(dev->priv, &parms);
	} else if (strcmp(entry->name, FILENAME_MODE) == 0) {
		if (comx_strcasecmp(page, "dte") == 0) {
			parms.mode &= ~(LAPB_DCE | LAPB_DTE); 
			parms.mode |= LAPB_DTE;
		} else if (comx_strcasecmp(page, "dce") == 0) {
			parms.mode &= ~(LAPB_DTE | LAPB_DCE); 
			parms.mode |= LAPB_DCE;
		} else if (comx_strcasecmp(page, "std") == 0 || 
		    comx_strcasecmp(page, "standard") == 0) {
			parms.mode &= ~LAPB_EXTENDED; 
			parms.mode |= LAPB_STANDARD;
		} else if (comx_strcasecmp(page, "ext") == 0 || 
		    comx_strcasecmp(page, "extended") == 0) {
			parms.mode &= ~LAPB_STANDARD; 
			parms.mode |= LAPB_EXTENDED;
		}
		lapb_setparms(dev->priv, &parms);
	} else {
		printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n", 
			entry->name);
		return -EBADF;
	}

	free_page((unsigned long)page);
	return count;
}
Ejemplo n.º 2
0
Archivo: comx.c Proyecto: nhanh0/hah
static int comx_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 = (struct net_device *)entry->parent->data;
    struct comx_channel *ch=(struct comx_channel *)dev->priv;
    char *page;
    struct comx_hardware *hw = comx_channels;
    struct comx_protocol *line = comx_lines;
    char str[30];
    int ret=0;

    if (count > PAGE_SIZE) {
        printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
        return -ENOSPC;
    }

    if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;

    if(copy_from_user(page, buffer, count))
    {
        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;
    }

    if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
        int i;
        int ret = 0;

        if ((i = simple_strtoul(page, NULL, 10)) != 0) {
            unsigned long flags;

            save_flags(flags);
            cli();
            if (ch->debug_area) kfree(ch->debug_area);
            if ((ch->debug_area = kmalloc(ch->debug_size = i,
                                          GFP_KERNEL)) == NULL) {
                ret = -ENOMEM;
            }
            ch->debug_start = ch->debug_end = 0;
            restore_flags(flags);
            free_page((unsigned long)page);
            return ret ? ret : count;
        }

        if (*page != '+' && *page != '-') {
            free_page((unsigned long)page);
            return -EINVAL;
        }
        while (comx_debugflags[i].value &&
                strncmp(comx_debugflags[i].name, page + 1,
                        strlen(comx_debugflags[i].name))) {
            i++;
        }

        if (comx_debugflags[i].value == 0) {
            printk(KERN_ERR "Invalid debug option\n");
            free_page((unsigned long)page);
            return -EINVAL;
        }
        if (*page == '+') {
            ch->debug_flags |= comx_debugflags[i].value;
        } else {
            ch->debug_flags &= ~comx_debugflags[i].value;
        }
    } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
        if(strlen(page)>10) {
            free_page((unsigned long)page);
            return -EINVAL;
        }
        while (hw) {
            if (strcmp(hw->name, page) == 0) {
                break;
            } else {
                hw = hw->next;
            }
        }
#ifdef CONFIG_KMOD
        if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0) {
            sprintf(str,"comx-hw-%s",page);
            request_module(str);
        }
        hw=comx_channels;
        while (hw) {
            if (comx_strcasecmp(hw->name, page) == 0) {
                break;
            } else {
                hw = hw->next;
            }
        }
#endif

        if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw)  {
            free_page((unsigned long)page);
            return -ENODEV;
        }
        if (ch->init_status & HW_OPEN) {
            free_page((unsigned long)page);
            return -EBUSY;
        }
        if (ch->hardware && ch->hardware->hw_exit &&
                (ret=ch->hardware->hw_exit(dev))) {
            free_page((unsigned long)page);
            return ret;
        }
        ch->hardware = hw;
        entry->size = strlen(page) + 1;
        if (hw && hw->hw_init) hw->hw_init(dev);
    } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
        if(strlen(page)>10) {
            free_page((unsigned long)page);
            return -EINVAL;
        }
        while (line) {
            if (comx_strcasecmp(line->name, page) == 0) {
                break;
            } else {
                line = line->next;
            }
        }
#ifdef CONFIG_KMOD
        if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
            sprintf(str,"comx-proto-%s",page);
            request_module(str);
        }
        line=comx_lines;
        while (line) {
            if (comx_strcasecmp(line->name, page) == 0) {
                break;
            } else {
                line = line->next;
            }
        }
#endif

        if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
            free_page((unsigned long)page);
            return -ENODEV;
        }

        if (ch->init_status & LINE_OPEN) {
            free_page((unsigned long)page);
            return -EBUSY;
        }

        if (ch->protocol && ch->protocol->line_exit &&
                (ret=ch->protocol->line_exit(dev))) {
            free_page((unsigned long)page);
            return ret;
        }
        ch->protocol = line;
        entry->size = strlen(page) + 1;
        comx_reset_dev(dev);
        if (line && line->line_init) line->line_init(dev);
    } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
        int i;

        if ((i = simple_strtoul(page, NULL, 10)) != 0) {
            if (i >=0 && i < 10) {
                ch->lineup_delay = i;
            } else {
                printk(KERN_ERR "comx: invalid lineup_delay value\n");
            }
        }
    }
out:
    free_page((unsigned long)page);
    return count;
}