示例#1
0
static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action, 
			     struct attribute *attr, int gfp_mask)
{
	char *path;
	char *attrpath;
	char *signal;
	int len;
	int rc = -ENOMEM;

	path = kobject_get_path(kobj, gfp_mask);
	if (!path)
		return -ENOMEM;

	signal = action_to_string(action);
	if (!signal)
		return -EINVAL;

	if (attr) {
		len = strlen(path);
		len += strlen(attr->name) + 2;
		attrpath = kmalloc(len, gfp_mask);
		if (!attrpath)
			goto exit;
		sprintf(attrpath, "%s/%s", path, attr->name);
		rc = send_uevent(signal, attrpath, NULL, gfp_mask);
		kfree(attrpath);
	} else
		rc = send_uevent(signal, path, NULL, gfp_mask);

exit:
	kfree(path);
	return rc;
}
示例#2
0
// USBIF , to send IF uevent
int usbif_u3d_test_send_event(char* event)
{	
	char udev_event[128];
	char *envp[] = {udev_event, NULL };
	int ret ;

	snprintf(udev_event, 128, "USBIF_EVENT=%s",event);
	printk("usbif_u3d_test_send_event - sending %s event - %s in %s\n", udev_event, kobject_get_path(&mu3d_test_uevent_device.this_device->kobj, GFP_KERNEL));
	ret = kobject_uevent_env(&mu3d_test_uevent_device.this_device->kobj, KOBJ_CHANGE, envp);	
	if (ret < 0)
		printk("mu3d_test_uevent_device sending failed with ret = %d, \n", ret);
		
	return ret;
}
示例#3
0
/**
 * kobject_hotplug - notify userspace by executing /sbin/hotplug
 *
 * @action: action that is happening (usually "ADD" or "REMOVE")
 * @kobj: struct kobject that the action is happening to
 */
void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
{
	char *argv [3];
	char **envp = NULL;
	char *buffer = NULL;
	char *seq_buff;
	char *scratch;
	int i = 0;
	int retval;
	char *kobj_path = NULL;
	char *name = NULL;
	char *action_string;
#ifdef CONFIG_MOT_FEAT_HOTPLUG_FILTER
        char *filter = NULL;
#endif
	u64 seq;
	struct kobject *top_kobj = kobj;
	struct kset *kset;
	static struct kset_hotplug_ops null_hotplug_ops;
	struct kset_hotplug_ops *hotplug_ops = &null_hotplug_ops;

	/* If this kobj does not belong to a kset,
	   try to find a parent that does. */
	if (!top_kobj->kset && top_kobj->parent) {
		do {
			top_kobj = top_kobj->parent;
		} while (!top_kobj->kset && top_kobj->parent);
	}

	if (top_kobj->kset)
		kset = top_kobj->kset;
	else
		return;

	if (kset->hotplug_ops)
		hotplug_ops = kset->hotplug_ops;

	/* If the kset has a filter operation, call it.
	   Skip the event, if the filter returns zero. */
	if (hotplug_ops->filter) {
		if (!hotplug_ops->filter(kset, kobj))
			return;
	}

	pr_debug ("%s\n", __FUNCTION__);

	action_string = action_to_string(action);
	if (!action_string)
		return;

	envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
	if (!envp)
		return;
	memset (envp, 0x00, NUM_ENVP * sizeof (char *));

	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
	if (!buffer)
		goto exit;

	if (hotplug_ops->name)
		name = hotplug_ops->name(kset, kobj);
	if (name == NULL)
		name = kset->kobj.name;

#ifdef CONFIG_MOT_FEAT_HOTPLUG_FILTER
	if (hotplug_filters) {
		for ( filter = hotplug_filters; *filter != '\0'; ) {
			if (!strcmp(filter, name))
				break;
			filter += strlen(filter) + 1;
		}
		if (*filter == '\0')
			goto exit;
	} else {
		/* default state is to filter all events */
		goto exit;
	}
#endif

	argv [0] = hotplug_path;
	argv [1] = name;
	argv [2] = NULL;

	/* minimal command environment */
	envp [i++] = "HOME=/";
	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

	scratch = buffer;

	envp [i++] = scratch;
	scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;

	kobj_path = kobject_get_path(kobj, GFP_KERNEL);
	if (!kobj_path)
		goto exit;

	envp [i++] = scratch;
	scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;

	envp [i++] = scratch;
	scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1;

	/* reserve space for the sequence,
	 * put the real one in after the hotplug call */
	envp[i++] = seq_buff = scratch;
	scratch += strlen("SEQNUM=18446744073709551616") + 1;

	if (hotplug_ops->hotplug) {
		/* have the kset specific function add its stuff */
		retval = hotplug_ops->hotplug (kset, kobj,
				  &envp[i], NUM_ENVP - i, scratch,
				  BUFFER_SIZE - (scratch - buffer));
		if (retval) {
			pr_debug ("%s - hotplug() returned %d\n",
				  __FUNCTION__, retval);
			goto exit;
		}
	}

	spin_lock(&sequence_lock);
	seq = ++hotplug_seqnum;
	spin_unlock(&sequence_lock);
	sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);

	pr_debug ("%s: %s %s seq=%llu %s %s %s %s %s\n",
		  __FUNCTION__, argv[0], argv[1], (unsigned long long)seq,
		  envp[0], envp[1], envp[2], envp[3], envp[4]);

	send_uevent(action_string, kobj_path, envp, GFP_KERNEL);

	if (!hotplug_path[0])
		goto exit;

	retval = call_usermodehelper (argv[0], argv, envp, 0);
	if (retval)
		pr_debug ("%s - call_usermodehelper returned %d\n",
			  __FUNCTION__, retval);

exit:
	kfree(kobj_path);
	kfree(buffer);
	kfree(envp);
	return;
}
示例#4
0
/**
 * psb_kobject_uevent_env - send an uevent with environmental data
 *
 * @action: action that is happening
 * @kobj: struct kobject that the action is happening to
 * @envp_ext: pointer to environmental data
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
 */
int psb_kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
			   char *envp_ext[], int dst_group_id)
{
	struct kobj_uevent_env *env;
	const char *action_string = psb_kobject_actions[action];
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
	const struct kset_uevent_ops *uevent_ops;
	u64 seq;
	int i = 0;
	int retval = 0;

	pr_debug("kobject: '%s' (%p): %s\n",
		 kobject_name(kobj), kobj, __func__);

	/* search the kset we belong to */
	top_kobj = kobj;
	while (!top_kobj->kset && top_kobj->parent)
		top_kobj = top_kobj->parent;

	if (!top_kobj->kset) {
		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
			 "without kset!\n", kobject_name(kobj), kobj,
			 __func__);
		return -EINVAL;
	}

	kset = top_kobj->kset;
	uevent_ops = (const struct kset_uevent_ops *)kset->uevent_ops;

	/* skip the event, if uevent_suppress is set*/
	if (kobj->uevent_suppress) {
		pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
				 "caused the event to drop!\n",
				 kobject_name(kobj), kobj, __func__);
		return 0;
	}
	/* skip the event, if the filter returns zero. */
	if (uevent_ops && uevent_ops->filter)
		if (!uevent_ops->filter(kset, kobj)) {
			pr_debug("kobject: '%s' (%p): %s: filter function "
				 "caused the event to drop!\n",
				 kobject_name(kobj), kobj, __func__);
			return 0;
		}

	/* originating subsystem */
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	if (!subsystem) {
		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
			 "event to drop!\n", kobject_name(kobj), kobj,
			 __func__);
		return 0;
	}

	/* environment buffer */
	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
	if (!env)
		return -ENOMEM;

	/* complete object path */
	devpath = kobject_get_path(kobj, GFP_KERNEL);
	if (!devpath) {
		retval = -ENOENT;
		goto exit;
	}

	/* default keys */
	retval = add_uevent_var(env, "ACTION=%s", action_string);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
	if (retval)
		goto exit;

	/* keys passed in from the caller */
	if (envp_ext) {
		for (i = 0; envp_ext[i]; i++) {
			retval = add_uevent_var(env, "%s", envp_ext[i]);
			if (retval)
				goto exit;
		}
	}

	/* let the kset specific function add its stuff */
	if (uevent_ops && uevent_ops->uevent) {
		retval = uevent_ops->uevent(kset, kobj, env);
		if (retval) {
			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
				 "%d\n", kobject_name(kobj), kobj,
				 __func__, retval);
			goto exit;
		}
	}

	/*
	 * Mark "add" and "remove" events in the object to ensure proper
	 * events to userspace during automatic cleanup. If the object did
	 * send an "add" event, "remove" will automatically generated by
	 * the core, if not already done by the caller.
	 */
	if (action == KOBJ_ADD)
		kobj->state_add_uevent_sent = 1;
	else if (action == KOBJ_REMOVE)
		kobj->state_remove_uevent_sent = 1;

	/* we will send an event, so request a new sequence number */
	spin_lock(&sequence_lock);
	seq = ++psb_uevent_seqnum;
	spin_unlock(&sequence_lock);
	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
	if (retval)
		goto exit;

#if defined(CONFIG_NET)
	/* send netlink message */
	if (uevent_sock) {
		struct sk_buff *skb;
		size_t len;

		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
		if (skb) {
			char *scratch;

			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
			for (i = 0; i < env->envp_idx; i++) {
				len = strlen(env->envp[i]) + 1;
				scratch = skb_put(skb, len);
				strcpy(scratch, env->envp[i]);
			}

			NETLINK_CB(skb).dst_group = dst_group_id;
			retval = netlink_broadcast(uevent_sock, skb, 0,
						   dst_group_id,
						   GFP_KERNEL);

			/* ENOBUFS should be handled in userspace */
			if (retval == -ENOBUFS)
				retval = 0;
		} else
			retval = -ENOMEM;
	}
#endif

	/* call psb_uevent_helper, usually only enabled during early boot */
	if (psb_uevent_helper[0]) {
		char *argv[3];

		argv[0] = psb_uevent_helper;
		argv[1] = (char *)subsystem;
		argv[2] = NULL;
		retval = add_uevent_var(env, "HOME=/");
		if (retval)
			goto exit;
		retval = add_uevent_var(env,
					"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
		if (retval)
			goto exit;

		retval = call_usermodehelper(argv[0], argv,
					     env->envp, UMH_WAIT_EXEC);
	}

exit:
	kfree(devpath);
	kfree(env);
	return retval;
}
示例#5
0
/**
 * kobject_uevent_env - send an uevent with environmental data
 *
 * @action: action that is happening (usually KOBJ_MOVE)
 * @kobj: struct kobject that the action is happening to
 * @envp_ext: pointer to environmental data
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
 */
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
			char *envp_ext[])
{
	char **envp;
	char *buffer;
	char *scratch;
	const char *action_string;
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
	struct kset_uevent_ops *uevent_ops;
	u64 seq;
	char *seq_buff;
	int i = 0;
	int retval = 0;
	int j;

	pr_debug("%s\n", __FUNCTION__);

	action_string = action_to_string(action);
	if (!action_string) {
		pr_debug("kobject attempted to send uevent without action_string!\n");
		return -EINVAL;
	}

	/* search the kset we belong to */
	top_kobj = kobj;
	while (!top_kobj->kset && top_kobj->parent) {
		top_kobj = top_kobj->parent;
	}
	if (!top_kobj->kset) {
		pr_debug("kobject attempted to send uevent without kset!\n");
		return -EINVAL;
	}

	kset = top_kobj->kset;
	uevent_ops = kset->uevent_ops;

	/*  skip the event, if the filter returns zero. */
	if (uevent_ops && uevent_ops->filter)
		if (!uevent_ops->filter(kset, kobj)) {
			pr_debug("kobject filter function caused the event to drop!\n");
			return 0;
		}

	/* originating subsystem */
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	if (!subsystem) {
		pr_debug("unset subsytem caused the event to drop!\n");
		return 0;
	}

	/* environment index */
	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
	if (!envp)
		return -ENOMEM;

	/* environment values */
	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
	if (!buffer) {
		retval = -ENOMEM;
		goto exit;
	}

	/* complete object path */
	devpath = kobject_get_path(kobj, GFP_KERNEL);
	if (!devpath) {
		retval = -ENOENT;
		goto exit;
	}

	/* event environemnt for helper process only */
	envp[i++] = "HOME=/";
	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

	/* default keys */
	scratch = buffer;
	envp [i++] = scratch;
	scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
	envp [i++] = scratch;
	scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
	envp [i++] = scratch;
	scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
	for (j = 0; envp_ext && envp_ext[j]; j++)
		envp[i++] = envp_ext[j];
	/* just reserve the space, overwrite it after kset call has returned */
	envp[i++] = seq_buff = scratch;
	scratch += strlen("SEQNUM=18446744073709551616") + 1;

	/* let the kset specific function add its stuff */
	if (uevent_ops && uevent_ops->uevent) {
		retval = uevent_ops->uevent(kset, kobj,
				  &envp[i], NUM_ENVP - i, scratch,
				  BUFFER_SIZE - (scratch - buffer));
		if (retval) {
			pr_debug ("%s - uevent() returned %d\n",
				  __FUNCTION__, retval);
			goto exit;
		}
	}

	/* we will send an event, request a new sequence number */
	spin_lock(&sequence_lock);
	seq = ++uevent_seqnum;
	spin_unlock(&sequence_lock);
	sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);

#if defined(CONFIG_NET)
	/* send netlink message */
	if (uevent_sock) {
		struct sk_buff *skb;
		size_t len;

		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
		skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
		if (skb) {
			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
			for (i = 2; envp[i]; i++) {
				len = strlen(envp[i]) + 1;
				scratch = skb_put(skb, len);
				strcpy(scratch, envp[i]);
			}

			NETLINK_CB(skb).dst_group = 1;
			netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
		}
	}
#endif

	/* call uevent_helper, usually only enabled during early boot */
	if (uevent_helper[0]) {
		char *argv [3];

		argv [0] = uevent_helper;
		argv [1] = (char *)subsystem;
		argv [2] = NULL;
		call_usermodehelper (argv[0], argv, envp, 0);
	}

exit:
	kfree(devpath);
	kfree(buffer);
	kfree(envp);
	return retval;
}
示例#6
0
static int pixcir_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *interface = intf->cur_altsetting;
	struct usb_device *dev = interface_to_usbdev(intf);
	struct input_dev *input_dev1;

	int n = 0, insize = TOUCH_PACKAGE_LEN;
	int err;
 	const char *path;
 	int  len;
 	char input_buf[10];
	
 	struct pixcir_mt_usb *psmt = kzalloc(sizeof(struct pixcir_mt_usb), GFP_KERNEL);

	kref_init(&psmt->kref);
	mutex_init(&psmt->io_mutex);
	
  	printk("%s\n", __FUNCTION__);
	psmt->type = &type;
	psmt->udev = dev;

	if (dev->manufacturer)
    strlcpy(psmt->name, dev->manufacturer, sizeof(psmt->name));

	if (dev->product) {
    if (dev->manufacturer)
      strlcat(psmt->name, " ", sizeof(psmt->name));
    strlcat(psmt->name, dev->product, sizeof(psmt->name));
	}

	if (!strlen(psmt->name))
    snprintf(psmt->name, sizeof(psmt->name), "USB Touchscreen %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct));

	if (!psmt->type->process_pkt) {
    printk("process_pkt is null\n");
    psmt->type->process_pkt = usbtouch_process_pkt;
 	}

	usb_set_intfdata(intf, psmt);
	
	err = usb_register_dev(intf,&pixcir_class_driver);
	if(err){
		printk("Not able to get minor for this device.");
	}

	dev_info(&intf->dev,"now attach to USB-%d",intf->minor);	

	input_dev1 = input_allocate_device();
	input_dev1->name = "pixcir_usb_ts";
	usb_to_input_id(dev, &input_dev1->id);
	psmt->input_dev = input_dev1;

	if(!psmt|| !input_dev1) {
    printk("Memory is not enough\n");
    goto fail1;
	}

	input_dev1->dev.parent = &intf->dev;
	input_set_drvdata(input_dev1, psmt);

	set_bit(EV_SYN, input_dev1->evbit);
	set_bit(EV_KEY, input_dev1->evbit);
	set_bit(EV_ABS, input_dev1->evbit);
	set_bit(BTN_TOUCH, input_dev1->keybit);
	input_set_abs_params(input_dev1, ABS_X, psmt->type->min_xc, psmt->type->max_xc, 0, 0);
	input_set_abs_params(input_dev1, ABS_Y, psmt->type->min_yc, psmt->type->max_yc, 0, 0);
	input_set_abs_params(input_dev1, ABS_MT_POSITION_X, psmt->type->min_xc, psmt->type->max_xc, 0, 0);
	input_set_abs_params(input_dev1, ABS_MT_POSITION_Y, psmt->type->min_yc, psmt->type->max_yc, 0, 0);
  input_set_abs_params(input_dev1, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
  input_set_abs_params(input_dev1, ABS_MT_WIDTH_MAJOR, 0, 25, 0, 0);

  psmt->data = usb_alloc_coherent(dev, insize, GFP_KERNEL, &psmt->data_dma);

  if(!psmt->data) {
    printk("psmt->data allocating fail");
    goto fail;
  }

  for (n = 0; n < interface->desc.bNumEndpoints; n++) {
    struct usb_endpoint_descriptor *endpoint;
    int pipe;
    int interval;

    endpoint = &interface->endpoint[n].desc;


		/*find a int endpoint*/
    if (!usb_endpoint_xfer_int(endpoint))
                   continue;

    interval = endpoint->bInterval;
    if (usb_endpoint_dir_in(endpoint)) {
      if (psmt->urb)
        continue;
      if (!(psmt->urb = usb_alloc_urb(0, GFP_KERNEL)))
        goto fail;

      pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
      usb_fill_int_urb(psmt->urb, dev, pipe, psmt->data, insize, pixcir_mt_irq, psmt, interval);
      psmt->urb->transfer_dma = psmt->data_dma;
      psmt->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
    }
  }


  if (usb_submit_urb(psmt->urb, GFP_ATOMIC)) {
    printk("usb submit urb error\n");
    return -EIO;
  }

  err = input_register_device(psmt->input_dev);
  if(err) {
    printk("pixcir_probe: Could not register input device(touchscreen)!\n");
      return -EIO;
  }

  path = kobject_get_path(&psmt->input_dev->dev.kobj, GFP_KERNEL);
  len=strlen(path);
  if(len>10){
		if(path[len-2]=='t'){
			memset(input_buf,'\0',9);
			strncpy(input_buf,&path[len-6],6);
		}else if(path[len-3]=='t'){
			memset(input_buf,'\0',9);
			strncpy(input_buf,&path[len-7],7);
		}else{
			 goto fail;
		}
  }else{
     	    goto fail;
  }

  usb_make_path(dev, psmt->phys0, sizeof(psmt->phys0));
  strlcat(psmt->phys0,input_buf, sizeof(psmt->phys0));

  return 0;

fail:
  usb_free_urb(psmt->urb);
  psmt->urb = NULL;
  usb_free_coherent(dev, insize, psmt->data, psmt->data_dma);
fail1:
  input_free_device(input_dev1);
  kfree(psmt);
  return 1;
}
示例#7
0
// dyc: build env-variable array, increase uevent_seqnum, 
//      then send netlink message or call hotplug
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
		       char *envp_ext[])
{
	struct kobj_uevent_env *env;
	const char *action_string = kobject_actions[action];
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
	struct kset_uevent_ops *uevent_ops;
	u64 seq;
	int i = 0;
	int retval = 0;

	pr_debug("%s\n", __FUNCTION__);

	/* search the kset we belong to */
	top_kobj = kobj;
	while (!top_kobj->kset && top_kobj->parent)
		top_kobj = top_kobj->parent;

    // dyc: so, top_kob must no parent while belong to a kset
	if (!top_kobj->kset) {
		pr_debug("kobject attempted to send uevent without kset!\n");
		return -EINVAL;
	}

    // dyc: finally what we need is an ancient kset
	kset = top_kobj->kset;
	uevent_ops = kset->uevent_ops;

	/* skip the event, if the filter returns zero. */
	if (uevent_ops && uevent_ops->filter)
		if (!uevent_ops->filter(kset, kobj)) {
			pr_debug("kobject filter function caused the event to drop!\n");
			return 0;
		}

	/* originating subsystem */
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	if (!subsystem) {
		pr_debug("unset subsystem caused the event to drop!\n");
		return 0;
	}

	/* environment buffer */
	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
	if (!env)
		return -ENOMEM;

	/* complete object path */
    // dyc: walk path, malloc buffer, assign kobj's full path and return 
	devpath = kobject_get_path(kobj, GFP_KERNEL);
	if (!devpath) {
		retval = -ENOENT;
		goto exit;
	}

	/* default keys */
    // dyc: assign key-values to env->buffer
	retval = add_uevent_var(env, "ACTION=%s", action_string);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
	if (retval)
		goto exit;

	/* keys passed in from the caller */
    // dyc: copy env-variable passed in by caller
	if (envp_ext) {
		for (i = 0; envp_ext[i]; i++) {
			retval = add_uevent_var(env, envp_ext[i]);
			if (retval)
				goto exit;
		}
	}

	/* let the kset specific function add its stuff */
	if (uevent_ops && uevent_ops->uevent) {
		retval = uevent_ops->uevent(kset, kobj, env);
		if (retval) {
			pr_debug ("%s - uevent() returned %d\n",
				  __FUNCTION__, retval);
			goto exit;
		}
	}

	/* we will send an event, so request a new sequence number */
	spin_lock(&sequence_lock);
    // dyc: increase global variable
	seq = ++uevent_seqnum;
	spin_unlock(&sequence_lock);
	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
	if (retval)
		goto exit;

#if defined(CONFIG_NET)
	/* send netlink message */
	if (uevent_sock) {
		struct sk_buff *skb;
		size_t len;

		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
		if (skb) {
			char *scratch;

			/* add header */
            // dyc: return buffer's tail and extend length with param [len]
			scratch = skb_put(skb, len);
			sprintf(scratch, "%s@%s", action_string, devpath);

			/* copy keys to our continuous event payload buffer */
			for (i = 0; i < env->envp_idx; i++) {
				len = strlen(env->envp[i]) + 1;
				scratch = skb_put(skb, len);
				strcpy(scratch, env->envp[i]);
			}

			NETLINK_CB(skb).dst_group = 1;
			netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
		}
	}
#endif

	/* call uevent_helper, usually only enabled during early boot */
    // dyc: It is said that, usually uevent_helper is /sbin/hotplug
    //      and when we use netlink socket, we don't need hotplug any more
	if (uevent_helper[0]) {
		char *argv [3];

		argv [0] = uevent_helper;
		argv [1] = (char *)subsystem;
		argv [2] = NULL;
		retval = add_uevent_var(env, "HOME=/");
		if (retval)
			goto exit;
		retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
		if (retval)
			goto exit;

		call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
	}

exit:
	kfree(devpath);
	kfree(env);
	return retval;
}
示例#8
0
/**
 * kobject_hotplug - notify userspace by executing /sbin/hotplug
 *
 * @action: action that is happening (usually "ADD" or "REMOVE")
 * @kobj: struct kobject that the action is happening to
 */
void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
{
	char *argv [3];
	char **envp = NULL;
	char *buffer = NULL;
	char *scratch;
	int i = 0;
	int retval;
	char *kobj_path = NULL;
	char *name = NULL;
	char *action_string;
	u64 seq;
	struct kobject *top_kobj = kobj;
	struct kset *kset;

	if (!top_kobj->kset && top_kobj->parent) {
		do {
			top_kobj = top_kobj->parent;
		} while (!top_kobj->kset && top_kobj->parent);
	}

	if (top_kobj->kset && top_kobj->kset->hotplug_ops)
		kset = top_kobj->kset;
	else
		return;

	/* If the kset has a filter operation, call it.
	   Skip the event, if the filter returns zero. */
	if (kset->hotplug_ops->filter) {
		if (!kset->hotplug_ops->filter(kset, kobj))
			return;
	}

	pr_debug ("%s\n", __FUNCTION__);

	action_string = action_to_string(action);
	if (!action_string)
		return;

	envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
	if (!envp)
		return;
	memset (envp, 0x00, NUM_ENVP * sizeof (char *));

	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
	if (!buffer)
		goto exit;

	if (kset->hotplug_ops->name)
		name = kset->hotplug_ops->name(kset, kobj);
	if (name == NULL)
		name = kset->kobj.name;

	argv [0] = hotplug_path;
	argv [1] = name;
	argv [2] = NULL;

	/* minimal command environment */
	envp [i++] = "HOME=/";
	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

	scratch = buffer;

	envp [i++] = scratch;
	scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;

	kobj_path = kobject_get_path(kobj, GFP_KERNEL);
	if (!kobj_path)
		goto exit;

	envp [i++] = scratch;
	scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;

	spin_lock(&sequence_lock);
	seq = ++hotplug_seqnum;
	spin_unlock(&sequence_lock);

	envp [i++] = scratch;
	scratch += sprintf(scratch, "SEQNUM=%lld", (long long)seq) + 1;

	envp [i++] = scratch;
	scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1;

	if (kset->hotplug_ops->hotplug) {
		/* have the kset specific function add its stuff */
		retval = kset->hotplug_ops->hotplug (kset, kobj,
				  &envp[i], NUM_ENVP - i, scratch,
				  BUFFER_SIZE - (scratch - buffer));
		if (retval) {
			pr_debug ("%s - hotplug() returned %d\n",
				  __FUNCTION__, retval);
			goto exit;
		}
	}

	pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
		  envp[0], envp[1], envp[2], envp[3], envp[4]);

	send_uevent(action_string, kobj_path, buffer, scratch - buffer, GFP_KERNEL);

	if (!hotplug_path[0])
		goto exit;

	retval = call_usermodehelper (argv[0], argv, envp, 0);
	if (retval)
		pr_debug ("%s - call_usermodehelper returned %d\n",
			  __FUNCTION__, retval);

exit:
	kfree(kobj_path);
	kfree(buffer);
	kfree(envp);
	return;
}
示例#9
0
文件: uinput.c 项目: bentiss/uinput
static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
				 unsigned long arg, void __user *p)
{
	int			retval;
	struct uinput_device	*udev = file->private_data;
	struct uinput_ff_upload ff_up;
	struct uinput_ff_erase  ff_erase;
	struct uinput_request   *req;
	char			*phys;
	const char		*path;
	unsigned int		size;

	retval = mutex_lock_interruptible(&udev->mutex);
	if (retval)
		return retval;

	if (!udev->dev) {
		retval = uinput_allocate_device(udev);
		if (retval)
			goto out;
	}

	switch (cmd) {
		case UI_DEV_CREATE:
			retval = uinput_create_device(udev);
			break;

		case UI_DEV_DESTROY:
			uinput_destroy_device(udev);
			break;

		case UI_SET_EVBIT:
			retval = uinput_set_bit(arg, evbit, EV_MAX);
			break;

		case UI_SET_KEYBIT:
			retval = uinput_set_bit(arg, keybit, KEY_MAX);
			break;

		case UI_SET_RELBIT:
			retval = uinput_set_bit(arg, relbit, REL_MAX);
			break;

		case UI_SET_ABSBIT:
			retval = uinput_set_bit(arg, absbit, ABS_MAX);
			break;

		case UI_SET_MSCBIT:
			retval = uinput_set_bit(arg, mscbit, MSC_MAX);
			break;

		case UI_SET_LEDBIT:
			retval = uinput_set_bit(arg, ledbit, LED_MAX);
			break;

		case UI_SET_SNDBIT:
			retval = uinput_set_bit(arg, sndbit, SND_MAX);
			break;

		case UI_SET_FFBIT:
			retval = uinput_set_bit(arg, ffbit, FF_MAX);
			break;

		case UI_SET_SWBIT:
			retval = uinput_set_bit(arg, swbit, SW_MAX);
			break;

		case UI_SET_PROPBIT:
#ifdef INPUT_PROP_MAX
			retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
#else /* INPUT_PROP_MAX */
			retval = -EINVAL;
#endif /* INPUT_PROP_MAX */
			break;

		case UI_SET_PHYS:
			if (udev->state == UIST_CREATED) {
				retval = -EINVAL;
				goto out;
			}

			phys = strndup_user(p, 1024);
			if (IS_ERR(phys)) {
				retval = PTR_ERR(phys);
				goto out;
			}

			kfree(udev->dev->phys);
			udev->dev->phys = phys;
			break;

		case UI_BEGIN_FF_UPLOAD:
			retval = uinput_ff_upload_from_user(p, &ff_up);
			if (retval)
				break;

			req = uinput_request_find(udev, ff_up.request_id);
			if (!req || req->code != UI_FF_UPLOAD ||
			    !req->u.upload.effect) {
				retval = -EINVAL;
				break;
			}

			ff_up.retval = 0;
			ff_up.effect = *req->u.upload.effect;
			if (req->u.upload.old)
				ff_up.old = *req->u.upload.old;
			else
				memset(&ff_up.old, 0, sizeof(struct ff_effect));

			retval = uinput_ff_upload_to_user(p, &ff_up);
			break;

		case UI_BEGIN_FF_ERASE:
			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
				retval = -EFAULT;
				break;
			}

			req = uinput_request_find(udev, ff_erase.request_id);
			if (!req || req->code != UI_FF_ERASE) {
				retval = -EINVAL;
				break;
			}

			ff_erase.retval = 0;
			ff_erase.effect_id = req->u.effect_id;
			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
				retval = -EFAULT;
				break;
			}

			break;

		case UI_END_FF_UPLOAD:
			retval = uinput_ff_upload_from_user(p, &ff_up);
			if (retval)
				break;

			req = uinput_request_find(udev, ff_up.request_id);
			if (!req || req->code != UI_FF_UPLOAD ||
			    !req->u.upload.effect) {
				retval = -EINVAL;
				break;
			}

			req->retval = ff_up.retval;
			uinput_request_done(udev, req);
			break;

		case UI_END_FF_ERASE:
			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
				retval = -EFAULT;
				break;
			}

			req = uinput_request_find(udev, ff_erase.request_id);
			if (!req || req->code != UI_FF_ERASE) {
				retval = -EINVAL;
				break;
			}

			req->retval = ff_erase.retval;
			uinput_request_done(udev, req);
			break;

		default:
			retval = -EAGAIN;
	}

	if (retval == -EAGAIN) {
		size = _IOC_SIZE(cmd);

		/* Now check variable-length commands */
		switch (cmd & ~IOCSIZE_MASK) {
			case UI_GET_SYSPATH(0):
				path = kobject_get_path(&udev->dev->dev.kobj,
							GFP_KERNEL);
				retval = uinput_str_to_user(path, size, p);
				kfree(path);
				break;

			default:
				retval = -EINVAL;
		}
	}

 out:
	mutex_unlock(&udev->mutex);
	return retval;
}