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; }
// 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
// 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; }
/** * 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; }
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; }