brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · a157238 Raw
305 lines · c
1// SPDX-License-Identifier: GPL-2.0+2// Driver for Xbox DVD Movie Playback Kit3// Copyright (c) 2018 by Benjamin Valentin <benpicco@googlemail.com>4 5/*6 *  Xbox DVD Movie Playback Kit USB IR dongle support7 *8 *  The driver was derived from the ati_remote driver 2.2.19 *          and used information from lirc_xbox.c10 *11 *          Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>12 *          Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>13 *          Copyright (c) 2002 Vladimir Dergachev14 *          Copyright (c) 2003-2004 Paul Miller <pmiller9@users.sourceforge.net>15 */16 17#include <linux/slab.h>18#include <linux/module.h>19#include <linux/usb/input.h>20#include <media/rc-core.h>21 22/*23 * Module and Version Information24 */25#define DRIVER_VERSION	"1.0.0"26#define DRIVER_AUTHOR	"Benjamin Valentin <benpicco@googlemail.com>"27#define DRIVER_DESC		"Xbox DVD USB Remote Control"28 29#define NAME_BUFSIZE      80    /* size of product name, path buffers */30#define DATA_BUFSIZE      8     /* size of URB data buffers */31 32/*33 * USB vendor ids for XBOX DVD Dongles34 */35#define VENDOR_GAMESTER     0x040b36#define VENDOR_MICROSOFT    0x045e37 38static const struct usb_device_id xbox_remote_table[] = {39	/* Gamester Xbox DVD Movie Playback Kit IR */40	{41		USB_DEVICE(VENDOR_GAMESTER, 0x6521),42	},43	/* Microsoft Xbox DVD Movie Playback Kit IR */44	{45		USB_DEVICE(VENDOR_MICROSOFT, 0x0284),46	},47	{}	/* Terminating entry */48};49 50MODULE_DEVICE_TABLE(usb, xbox_remote_table);51 52struct xbox_remote {53	struct rc_dev *rdev;54	struct usb_device *udev;55	struct usb_interface *interface;56 57	struct urb *irq_urb;58	unsigned char inbuf[DATA_BUFSIZE] __aligned(sizeof(u16));59 60	char rc_name[NAME_BUFSIZE];61	char rc_phys[NAME_BUFSIZE];62};63 64static int xbox_remote_rc_open(struct rc_dev *rdev)65{66	struct xbox_remote *xbox_remote = rdev->priv;67 68	/* On first open, submit the read urb which was set up previously. */69	xbox_remote->irq_urb->dev = xbox_remote->udev;70	if (usb_submit_urb(xbox_remote->irq_urb, GFP_KERNEL)) {71		dev_err(&xbox_remote->interface->dev,72			"%s: usb_submit_urb failed!\n", __func__);73		return -EIO;74	}75 76	return 0;77}78 79static void xbox_remote_rc_close(struct rc_dev *rdev)80{81	struct xbox_remote *xbox_remote = rdev->priv;82 83	usb_kill_urb(xbox_remote->irq_urb);84}85 86/*87 * xbox_remote_report_input88 */89static void xbox_remote_input_report(struct urb *urb)90{91	struct xbox_remote *xbox_remote = urb->context;92	unsigned char *data = xbox_remote->inbuf;93 94	/*95	 * data[0] = 0x0096	 * data[1] = length - always 0x0697	 * data[2] = the key code98	 * data[3] = high part of key code99	 * data[4] = last_press_ms (low)100	 * data[5] = last_press_ms (high)101	 */102 103	/* Deal with strange looking inputs */104	if (urb->actual_length != 6 || urb->actual_length != data[1]) {105		dev_warn(&urb->dev->dev, "Weird data, len=%d: %*ph\n",106			 urb->actual_length, urb->actual_length, data);107		return;108	}109 110	rc_keydown(xbox_remote->rdev, RC_PROTO_XBOX_DVD,111		   le16_to_cpup((__le16 *)(data + 2)), 0);112}113 114/*115 * xbox_remote_irq_in116 */117static void xbox_remote_irq_in(struct urb *urb)118{119	struct xbox_remote *xbox_remote = urb->context;120	int retval;121 122	switch (urb->status) {123	case 0:			/* success */124		xbox_remote_input_report(urb);125		break;126	case -ECONNRESET:	/* unlink */127	case -ENOENT:128	case -ESHUTDOWN:129		dev_dbg(&xbox_remote->interface->dev,130			"%s: urb error status, unlink?\n",131			__func__);132		return;133	default:		/* error */134		dev_dbg(&xbox_remote->interface->dev,135			"%s: Nonzero urb status %d\n",136			__func__, urb->status);137	}138 139	retval = usb_submit_urb(urb, GFP_ATOMIC);140	if (retval)141		dev_err(&xbox_remote->interface->dev,142			"%s: usb_submit_urb()=%d\n",143			__func__, retval);144}145 146static void xbox_remote_rc_init(struct xbox_remote *xbox_remote)147{148	struct rc_dev *rdev = xbox_remote->rdev;149 150	rdev->priv = xbox_remote;151	rdev->allowed_protocols = RC_PROTO_BIT_XBOX_DVD;152	rdev->driver_name = "xbox_remote";153 154	rdev->open = xbox_remote_rc_open;155	rdev->close = xbox_remote_rc_close;156 157	rdev->device_name = xbox_remote->rc_name;158	rdev->input_phys = xbox_remote->rc_phys;159 160	rdev->timeout = MS_TO_US(10);161 162	usb_to_input_id(xbox_remote->udev, &rdev->input_id);163	rdev->dev.parent = &xbox_remote->interface->dev;164}165 166static void xbox_remote_initialize(struct xbox_remote *xbox_remote,167				   struct usb_endpoint_descriptor *endpoint_in)168{169	struct usb_device *udev = xbox_remote->udev;170	int pipe, maxp;171 172	/* Set up irq_urb */173	pipe = usb_rcvintpipe(udev, endpoint_in->bEndpointAddress);174	maxp = usb_maxpacket(udev, pipe);175	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;176 177	usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf,178			 maxp, xbox_remote_irq_in, xbox_remote,179			 endpoint_in->bInterval);180}181 182/*183 * xbox_remote_probe184 */185static int xbox_remote_probe(struct usb_interface *interface,186			     const struct usb_device_id *id)187{188	struct usb_device *udev = interface_to_usbdev(interface);189	struct usb_host_interface *iface_host = interface->cur_altsetting;190	struct usb_endpoint_descriptor *endpoint_in;191	struct xbox_remote *xbox_remote;192	struct rc_dev *rc_dev;193	int err = -ENOMEM;194 195	// why is there also a device with no endpoints?196	if (iface_host->desc.bNumEndpoints == 0)197		return -ENODEV;198 199	if (iface_host->desc.bNumEndpoints != 1) {200		pr_err("%s: Unexpected desc.bNumEndpoints: %d\n",201		       __func__, iface_host->desc.bNumEndpoints);202		return -ENODEV;203	}204 205	endpoint_in = &iface_host->endpoint[0].desc;206 207	if (!usb_endpoint_is_int_in(endpoint_in)) {208		pr_err("%s: Unexpected endpoint_in\n", __func__);209		return -ENODEV;210	}211	if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {212		pr_err("%s: endpoint_in message size==0?\n", __func__);213		return -ENODEV;214	}215 216	xbox_remote = kzalloc(sizeof(*xbox_remote), GFP_KERNEL);217	rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);218	if (!xbox_remote || !rc_dev)219		goto exit_free_dev_rdev;220 221	/* Allocate URB buffer */222	xbox_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);223	if (!xbox_remote->irq_urb)224		goto exit_free_buffers;225 226	xbox_remote->udev = udev;227	xbox_remote->rdev = rc_dev;228	xbox_remote->interface = interface;229 230	usb_make_path(udev, xbox_remote->rc_phys, sizeof(xbox_remote->rc_phys));231 232	strlcat(xbox_remote->rc_phys, "/input0", sizeof(xbox_remote->rc_phys));233 234	snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name), "%s%s%s",235		 udev->manufacturer ?: "",236		 udev->manufacturer && udev->product ? " " : "",237		 udev->product ?: "");238 239	if (!strlen(xbox_remote->rc_name))240		snprintf(xbox_remote->rc_name, sizeof(xbox_remote->rc_name),241			 DRIVER_DESC "(%04x,%04x)",242			 le16_to_cpu(xbox_remote->udev->descriptor.idVendor),243			 le16_to_cpu(xbox_remote->udev->descriptor.idProduct));244 245	rc_dev->map_name = RC_MAP_XBOX_DVD; /* default map */246 247	xbox_remote_rc_init(xbox_remote);248 249	/* Device Hardware Initialization */250	xbox_remote_initialize(xbox_remote, endpoint_in);251 252	/* Set up and register rc device */253	err = rc_register_device(xbox_remote->rdev);254	if (err)255		goto exit_kill_urbs;256 257	usb_set_intfdata(interface, xbox_remote);258 259	return 0;260 261exit_kill_urbs:262	usb_kill_urb(xbox_remote->irq_urb);263exit_free_buffers:264	usb_free_urb(xbox_remote->irq_urb);265exit_free_dev_rdev:266	rc_free_device(rc_dev);267	kfree(xbox_remote);268 269	return err;270}271 272/*273 * xbox_remote_disconnect274 */275static void xbox_remote_disconnect(struct usb_interface *interface)276{277	struct xbox_remote *xbox_remote;278 279	xbox_remote = usb_get_intfdata(interface);280	usb_set_intfdata(interface, NULL);281	if (!xbox_remote) {282		dev_warn(&interface->dev, "%s - null device?\n", __func__);283		return;284	}285 286	usb_kill_urb(xbox_remote->irq_urb);287	rc_unregister_device(xbox_remote->rdev);288	usb_free_urb(xbox_remote->irq_urb);289	kfree(xbox_remote);290}291 292/* usb specific object to register with the usb subsystem */293static struct usb_driver xbox_remote_driver = {294	.name         = "xbox_remote",295	.probe        = xbox_remote_probe,296	.disconnect   = xbox_remote_disconnect,297	.id_table     = xbox_remote_table,298};299 300module_usb_driver(xbox_remote_driver);301 302MODULE_AUTHOR(DRIVER_AUTHOR);303MODULE_DESCRIPTION(DRIVER_DESC);304MODULE_LICENSE("GPL");305