Example #1
0
/**
 * pdcspath_layer_write - This function handles extended layer modifying.
 * @entry: An allocated and populated pdscpath_entry struct.
 * @buf: The input buffer to read from.
 * @count: The number of bytes to be read.
 * 
 * We will call this function to change the current layer value.
 * Layers are to be given '.'-delimited, without brackets.
 * XXX beware we are far less checky WRT input data provided than for hwpath.
 * Potential harm can be done, since there's no way to check the validity of
 * the layer fields.
 */
static ssize_t
pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count)
{
	unsigned int layers[6]; /* device-specific info (ctlr#, unit#, ...) */
	unsigned short i;
	char in[64], *temp;

	if (!entry || !buf || !count)
		return -EINVAL;

	/* We'll use a local copy of buf */
	count = min_t(size_t, count, sizeof(in)-1);
	strncpy(in, buf, count);
	in[count] = '\0';
	
	/* Let's clean up the target. 0 is a blank pattern */
	memset(&layers, 0, sizeof(layers));
	
	/* First, pick the first layer */
	if (unlikely(!isdigit(*in)))
		return -EINVAL;
	layers[0] = simple_strtoul(in, NULL, 10);
	DPRINTK("%s: layer[0]: %d\n", __func__, layers[0]);
	
	temp = in;
	for (i=1; ((temp = strchr(temp, '.'))) && (likely(i<6)); i++) {
		if (unlikely(!isdigit(*(++temp))))
			return -EINVAL;
		layers[i] = simple_strtoul(temp, NULL, 10);
		DPRINTK("%s: layer[%d]: %d\n", __func__, i, layers[i]);
	}
		
	/* So far so good, let's get in deep */
	write_lock(&entry->rw_lock);
	
	/* First, overwrite the current layers with the new ones, not touching
	   the hardware path. */
	memcpy(&entry->devpath.layers, &layers, sizeof(layers));
	
	/* Now, dive in. Write back to the hardware */
	pdcspath_store(entry);
	write_unlock(&entry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" layers to \"%s\"\n",
		entry->name, buf);
	
	return count;
}
static ssize_t
pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count)
{
	unsigned int layers[6]; 
	unsigned short i;
	char in[count+1], *temp;

	if (!entry || !buf || !count)
		return -EINVAL;

	
	memset(in, 0, count+1);
	strncpy(in, buf, count);
	
	
	memset(&layers, 0, sizeof(layers));
	
	
	if (unlikely(!isdigit(*in)))
		return -EINVAL;
	layers[0] = simple_strtoul(in, NULL, 10);
	DPRINTK("%s: layer[0]: %d\n", __func__, layers[0]);
	
	temp = in;
	for (i=1; ((temp = strchr(temp, '.'))) && (likely(i<6)); i++) {
		if (unlikely(!isdigit(*(++temp))))
			return -EINVAL;
		layers[i] = simple_strtoul(temp, NULL, 10);
		DPRINTK("%s: layer[%d]: %d\n", __func__, i, layers[i]);
	}
		
	
	write_lock(&entry->rw_lock);
	
	memcpy(&entry->devpath.layers, &layers, sizeof(layers));
	
	
	pdcspath_store(entry);
	write_unlock(&entry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" layers to \"%s\"\n",
		entry->name, buf);
	
	return count;
}
Example #3
0
/**
 * pdcs_auto_write - This function handles autoboot/search flag modifying.
 * @buf: The input buffer to read from.
 * @count: The number of bytes to be read.
 * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
 * 
 * We will call this function to change the current autoboot flag.
 * We expect a precise syntax:
 *	\"n\" (n == 0 or 1) to toggle AutoBoot Off or On
 */
static ssize_t pdcs_auto_write(struct kobject *kobj,
			       struct kobj_attribute *attr, const char *buf,
			       size_t count, int knob)
{
	struct pdcspath_entry *pathentry;
	unsigned char flags;
	char in[count+1], *temp;
	char c;

	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

	if (!buf || !count)
		return -EINVAL;

	/* We'll use a local copy of buf */
	memset(in, 0, count+1);
	strncpy(in, buf, count);

	/* Current flags are stored in primary boot path entry */
	pathentry = &pdcspath_entry_primary;
	
	/* Be nice to the existing flag record */
	read_lock(&pathentry->rw_lock);
	flags = pathentry->devpath.flags;
	read_unlock(&pathentry->rw_lock);
	
	DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
			
	temp = in;
	
	while (*temp && isspace(*temp))
		temp++;
	
	c = *temp++ - '0';
	if ((c != 0) && (c != 1))
		goto parse_error;
	if (c == 0)
		flags &= ~knob;
	else
		flags |= knob;
	
	DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
		
	/* So far so good, let's get in deep */
	write_lock(&pathentry->rw_lock);
	
	/* Change the path entry flags first */
	pathentry->devpath.flags = flags;
		
	/* Now, dive in. Write back to the hardware */
	pdcspath_store(pathentry);
	write_unlock(&pathentry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n",
		(knob & PF_AUTOBOOT) ? "autoboot" : "autosearch",
		(flags & knob) ? "On" : "Off");
	
	return count;

parse_error:
	printk(KERN_WARNING "%s: Parse error: expect \"n\" (n == 0 or 1)\n", __func__);
	return -EINVAL;
}
Example #4
0
/**
 * pdcspath_hwpath_write - This function handles hardware path modifying.
 * @entry: An allocated and populated pdscpath_entry struct.
 * @buf: The input buffer to read from.
 * @count: The number of bytes to be read.
 * 
 * We will call this function to change the current hardware path.
 * Hardware paths are to be given '/'-delimited, without brackets.
 * We make sure that the provided path actually maps to an existing
 * device, BUT nothing would prevent some foolish user to set the path to some
 * PCI bridge or even a CPU...
 * A better work around would be to make sure we are at the end of a device tree
 * for instance, but it would be IMHO beyond the simple scope of that driver.
 * The aim is to provide a facility. Data correctness is left to userland.
 */
static ssize_t
pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count)
{
	struct hardware_path hwpath;
	unsigned short i;
	char in[count+1], *temp;
	struct device *dev;
	int ret;

	if (!entry || !buf || !count)
		return -EINVAL;

	/* We'll use a local copy of buf */
	memset(in, 0, count+1);
	strncpy(in, buf, count);
	
	/* Let's clean up the target. 0xff is a blank pattern */
	memset(&hwpath, 0xff, sizeof(hwpath));
	
	/* First, pick the mod field (the last one of the input string) */
	if (!(temp = strrchr(in, '/')))
		return -EINVAL;
			
	hwpath.mod = simple_strtoul(temp+1, NULL, 10);
	in[temp-in] = '\0';	/* truncate the remaining string. just precaution */
	DPRINTK("%s: mod: %d\n", __func__, hwpath.mod);
	
	/* Then, loop for each delimiter, making sure we don't have too many.
	   we write the bc fields in a down-top way. No matter what, we stop
	   before writing the last field. If there are too many fields anyway,
	   then the user is a moron and it'll be caught up later when we'll
	   check the consistency of the given hwpath. */
	for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
		hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
		in[temp-in] = '\0';
		DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
	}
	
	/* Store the final field */		
	hwpath.bc[i] = simple_strtoul(in, NULL, 10);
	DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
	
	/* Now we check that the user isn't trying to lure us */
	if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
		printk(KERN_WARNING "%s: attempt to set invalid \"%s\" "
			"hardware path: %s\n", __func__, entry->name, buf);
		return -EINVAL;
	}
	
	/* So far so good, let's get in deep */
	write_lock(&entry->rw_lock);
	entry->ready = 0;
	entry->dev = dev;
	
	/* Now, dive in. Write back to the hardware */
	pdcspath_store(entry);
	
	/* Update the symlink to the real device */
	sysfs_remove_link(&entry->kobj, "device");
	ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
	WARN_ON(ret);

	write_unlock(&entry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
		entry->name, buf);
	
	return count;
}
static ssize_t pdcs_auto_write(struct kobject *kobj,
			       struct kobj_attribute *attr, const char *buf,
			       size_t count, int knob)
{
	struct pdcspath_entry *pathentry;
	unsigned char flags;
	char in[count+1], *temp;
	char c;

	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

	if (!buf || !count)
		return -EINVAL;

	
	memset(in, 0, count+1);
	strncpy(in, buf, count);

	
	pathentry = &pdcspath_entry_primary;
	
	
	read_lock(&pathentry->rw_lock);
	flags = pathentry->devpath.flags;
	read_unlock(&pathentry->rw_lock);
	
	DPRINTK("%s: flags before: 0x%X\n", __func__, flags);

	temp = skip_spaces(in);

	c = *temp++ - '0';
	if ((c != 0) && (c != 1))
		goto parse_error;
	if (c == 0)
		flags &= ~knob;
	else
		flags |= knob;
	
	DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
		
	
	write_lock(&pathentry->rw_lock);
	
	
	pathentry->devpath.flags = flags;
		
	
	pdcspath_store(pathentry);
	write_unlock(&pathentry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n",
		(knob & PF_AUTOBOOT) ? "autoboot" : "autosearch",
		(flags & knob) ? "On" : "Off");
	
	return count;

parse_error:
	printk(KERN_WARNING "%s: Parse error: expect \"n\" (n == 0 or 1)\n", __func__);
	return -EINVAL;
}
static ssize_t
pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t count)
{
	struct hardware_path hwpath;
	unsigned short i;
	char in[count+1], *temp;
	struct device *dev;
	int ret;

	if (!entry || !buf || !count)
		return -EINVAL;

	
	memset(in, 0, count+1);
	strncpy(in, buf, count);
	
	
	memset(&hwpath, 0xff, sizeof(hwpath));
	
	
	if (!(temp = strrchr(in, '/')))
		return -EINVAL;
			
	hwpath.mod = simple_strtoul(temp+1, NULL, 10);
	in[temp-in] = '\0';	
	DPRINTK("%s: mod: %d\n", __func__, hwpath.mod);
	
	for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
		hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
		in[temp-in] = '\0';
		DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
	}
	
			
	hwpath.bc[i] = simple_strtoul(in, NULL, 10);
	DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
	
	
	if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
		printk(KERN_WARNING "%s: attempt to set invalid \"%s\" "
			"hardware path: %s\n", __func__, entry->name, buf);
		return -EINVAL;
	}
	
	
	write_lock(&entry->rw_lock);
	entry->ready = 0;
	entry->dev = dev;
	
	
	pdcspath_store(entry);
	
	
	sysfs_remove_link(&entry->kobj, "device");
	ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
	WARN_ON(ret);

	write_unlock(&entry->rw_lock);
	
	printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
		entry->name, buf);
	
	return count;
}