diff options
Diffstat (limited to 'drivers/input/misc/ati_remote2.c')
| -rw-r--r-- | drivers/input/misc/ati_remote2.c | 277 | 
1 files changed, 261 insertions, 16 deletions
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 3c9988dc0e9..922c0514158 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -31,12 +31,73 @@ MODULE_LICENSE("GPL");   * newly configured "channel".   */ -static unsigned int channel_mask = 0xFFFF; -module_param(channel_mask, uint, 0644); +enum { +	ATI_REMOTE2_MAX_CHANNEL_MASK = 0xFFFF, +	ATI_REMOTE2_MAX_MODE_MASK = 0x1F, +}; + +static int ati_remote2_set_mask(const char *val, +				struct kernel_param *kp, unsigned int max) +{ +	unsigned long mask; +	int ret; + +	if (!val) +		return -EINVAL; + +	ret = strict_strtoul(val, 0, &mask); +	if (ret) +		return ret; + +	if (mask & ~max) +		return -EINVAL; + +	*(unsigned int *)kp->arg = mask; + +	return 0; +} + +static int ati_remote2_set_channel_mask(const char *val, +					struct kernel_param *kp) +{ +	pr_debug("%s()\n", __func__); + +	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK); +} + +static int ati_remote2_get_channel_mask(char *buffer, struct kernel_param *kp) +{ +	pr_debug("%s()\n", __func__); + +	return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg); +} + +static int ati_remote2_set_mode_mask(const char *val, struct kernel_param *kp) +{ +	pr_debug("%s()\n", __func__); + +	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK); +} + +static int ati_remote2_get_mode_mask(char *buffer, struct kernel_param *kp) +{ +	pr_debug("%s()\n", __func__); + +	return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg); +} + +static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK; +#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int) +#define param_set_channel_mask ati_remote2_set_channel_mask +#define param_get_channel_mask ati_remote2_get_channel_mask +module_param(channel_mask, channel_mask, 0644);  MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>"); -static unsigned int mode_mask = 0x1F; -module_param(mode_mask, uint, 0644); +static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK; +#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int) +#define param_set_mode_mask ati_remote2_set_mode_mask +#define param_get_mode_mask ati_remote2_get_mode_mask +module_param(mode_mask, mode_mask, 0644);  MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");  static struct usb_device_id ati_remote2_id_table[] = { @@ -133,12 +194,18 @@ struct ati_remote2 {  	u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];  	unsigned int flags; + +	unsigned int channel_mask; +	unsigned int mode_mask;  };  static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);  static void ati_remote2_disconnect(struct usb_interface *interface);  static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);  static int ati_remote2_resume(struct usb_interface *interface); +static int ati_remote2_reset_resume(struct usb_interface *interface); +static int ati_remote2_pre_reset(struct usb_interface *interface); +static int ati_remote2_post_reset(struct usb_interface *interface);  static struct usb_driver ati_remote2_driver = {  	.name       = "ati_remote2", @@ -147,6 +214,9 @@ static struct usb_driver ati_remote2_driver = {  	.id_table   = ati_remote2_id_table,  	.suspend    = ati_remote2_suspend,  	.resume     = ati_remote2_resume, +	.reset_resume = ati_remote2_reset_resume, +	.pre_reset  = ati_remote2_pre_reset, +	.post_reset = ati_remote2_post_reset,  	.supports_autosuspend = 1,  }; @@ -238,7 +308,7 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)  	channel = data[0] >> 4; -	if (!((1 << channel) & channel_mask)) +	if (!((1 << channel) & ar2->channel_mask))  		return;  	mode = data[0] & 0x0F; @@ -250,7 +320,7 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)  		return;  	} -	if (!((1 << mode) & mode_mask)) +	if (!((1 << mode) & ar2->mode_mask))  		return;  	input_event(idev, EV_REL, REL_X, (s8) data[1]); @@ -277,7 +347,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)  	channel = data[0] >> 4; -	if (!((1 << channel) & channel_mask)) +	if (!((1 << channel) & ar2->channel_mask))  		return;  	mode = data[0] & 0x0F; @@ -305,7 +375,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)  			ar2->mode = mode;  	} -	if (!((1 << mode) & mode_mask)) +	if (!((1 << mode) & ar2->mode_mask))  		return;  	index = ati_remote2_lookup(hw_code); @@ -410,7 +480,7 @@ static int ati_remote2_getkeycode(struct input_dev *idev,  	int index, mode;  	mode = scancode >> 8; -	if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask)) +	if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))  		return -EINVAL;  	index = ati_remote2_lookup(scancode & 0xFF); @@ -427,7 +497,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc  	int index, mode, old_keycode;  	mode = scancode >> 8; -	if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask)) +	if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask))  		return -EINVAL;  	index = ati_remote2_lookup(scancode & 0xFF); @@ -550,7 +620,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)  	}  } -static int ati_remote2_setup(struct ati_remote2 *ar2) +static int ati_remote2_setup(struct ati_remote2 *ar2, unsigned int ch_mask)  {  	int r, i, channel; @@ -565,8 +635,8 @@ static int ati_remote2_setup(struct ati_remote2 *ar2)  	channel = 0;  	for (i = 0; i < 16; i++) { -		if ((1 << i) & channel_mask) { -			if (!(~(1 << i) & 0xFFFF & channel_mask)) +		if ((1 << i) & ch_mask) { +			if (!(~(1 << i) & ch_mask))  				channel = i + 1;  			break;  		} @@ -585,6 +655,99 @@ static int ati_remote2_setup(struct ati_remote2 *ar2)  	return 0;  } +static ssize_t ati_remote2_show_channel_mask(struct device *dev, +					     struct device_attribute *attr, +					     char *buf) +{ +	struct usb_device *udev = to_usb_device(dev); +	struct usb_interface *intf = usb_ifnum_to_if(udev, 0); +	struct ati_remote2 *ar2 = usb_get_intfdata(intf); + +	return sprintf(buf, "0x%04x\n", ar2->channel_mask); +} + +static ssize_t ati_remote2_store_channel_mask(struct device *dev, +					      struct device_attribute *attr, +					      const char *buf, size_t count) +{ +	struct usb_device *udev = to_usb_device(dev); +	struct usb_interface *intf = usb_ifnum_to_if(udev, 0); +	struct ati_remote2 *ar2 = usb_get_intfdata(intf); +	unsigned long mask; +	int r; + +	if (strict_strtoul(buf, 0, &mask)) +		return -EINVAL; + +	if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK) +		return -EINVAL; + +	r = usb_autopm_get_interface(ar2->intf[0]); +	if (r) { +		dev_err(&ar2->intf[0]->dev, +			"%s(): usb_autopm_get_interface() = %d\n", __func__, r); +		return r; +	} + +	mutex_lock(&ati_remote2_mutex); + +	if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask)) +		ar2->channel_mask = mask; + +	mutex_unlock(&ati_remote2_mutex); + +	usb_autopm_put_interface(ar2->intf[0]); + +	return count; +} + +static ssize_t ati_remote2_show_mode_mask(struct device *dev, +					  struct device_attribute *attr, +					  char *buf) +{ +	struct usb_device *udev = to_usb_device(dev); +	struct usb_interface *intf = usb_ifnum_to_if(udev, 0); +	struct ati_remote2 *ar2 = usb_get_intfdata(intf); + +	return sprintf(buf, "0x%02x\n", ar2->mode_mask); +} + +static ssize_t ati_remote2_store_mode_mask(struct device *dev, +					   struct device_attribute *attr, +					   const char *buf, size_t count) +{ +	struct usb_device *udev = to_usb_device(dev); +	struct usb_interface *intf = usb_ifnum_to_if(udev, 0); +	struct ati_remote2 *ar2 = usb_get_intfdata(intf); +	unsigned long mask; + +	if (strict_strtoul(buf, 0, &mask)) +		return -EINVAL; + +	if (mask & ~ATI_REMOTE2_MAX_MODE_MASK) +		return -EINVAL; + +	ar2->mode_mask = mask; + +	return count; +} + +static DEVICE_ATTR(channel_mask, 0644, ati_remote2_show_channel_mask, +		   ati_remote2_store_channel_mask); + +static DEVICE_ATTR(mode_mask, 0644, ati_remote2_show_mode_mask, +		   ati_remote2_store_mode_mask); + +static struct attribute *ati_remote2_attrs[] = { +	&dev_attr_channel_mask.attr, +	&dev_attr_mode_mask.attr, +	NULL, +}; + +static struct attribute_group ati_remote2_attr_group = { +	.attrs = ati_remote2_attrs, +}; +  static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)  {  	struct usb_device *udev = interface_to_usbdev(interface); @@ -615,7 +778,10 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d  	if (r)  		goto fail2; -	r = ati_remote2_setup(ar2); +	ar2->channel_mask = channel_mask; +	ar2->mode_mask = mode_mask; + +	r = ati_remote2_setup(ar2, ar2->channel_mask);  	if (r)  		goto fail2; @@ -624,19 +790,24 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d  	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name)); -	r = ati_remote2_input_init(ar2); +	r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);  	if (r)  		goto fail2; +	r = ati_remote2_input_init(ar2); +	if (r) +		goto fail3; +  	usb_set_intfdata(interface, ar2);  	interface->needs_remote_wakeup = 1;  	return 0; + fail3: +	sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);   fail2:  	ati_remote2_urb_cleanup(ar2); -  	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);   fail1:  	kfree(ar2); @@ -657,6 +828,8 @@ static void ati_remote2_disconnect(struct usb_interface *interface)  	input_unregister_device(ar2->idev); +	sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group); +  	ati_remote2_urb_cleanup(ar2);  	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); @@ -715,6 +888,78 @@ static int ati_remote2_resume(struct usb_interface *interface)  	return r;  } +static int ati_remote2_reset_resume(struct usb_interface *interface) +{ +	struct ati_remote2 *ar2; +	struct usb_host_interface *alt = interface->cur_altsetting; +	int r = 0; + +	if (alt->desc.bInterfaceNumber) +		return 0; + +	ar2 = usb_get_intfdata(interface); + +	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); + +	mutex_lock(&ati_remote2_mutex); + +	r = ati_remote2_setup(ar2, ar2->channel_mask); +	if (r) +		goto out; + +	if (ar2->flags & ATI_REMOTE2_OPENED) +		r = ati_remote2_submit_urbs(ar2); + +	if (!r) +		ar2->flags &= ~ATI_REMOTE2_SUSPENDED; + + out: +	mutex_unlock(&ati_remote2_mutex); + +	return r; +} + +static int ati_remote2_pre_reset(struct usb_interface *interface) +{ +	struct ati_remote2 *ar2; +	struct usb_host_interface *alt = interface->cur_altsetting; + +	if (alt->desc.bInterfaceNumber) +		return 0; + +	ar2 = usb_get_intfdata(interface); + +	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); + +	mutex_lock(&ati_remote2_mutex); + +	if (ar2->flags == ATI_REMOTE2_OPENED) +		ati_remote2_kill_urbs(ar2); + +	return 0; +} + +static int ati_remote2_post_reset(struct usb_interface *interface) +{ +	struct ati_remote2 *ar2; +	struct usb_host_interface *alt = interface->cur_altsetting; +	int r = 0; + +	if (alt->desc.bInterfaceNumber) +		return 0; + +	ar2 = usb_get_intfdata(interface); + +	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); + +	if (ar2->flags == ATI_REMOTE2_OPENED) +		r = ati_remote2_submit_urbs(ar2); + +	mutex_unlock(&ati_remote2_mutex); + +	return r; +} +  static int __init ati_remote2_init(void)  {  	int r;  |