xref: /openbmc/linux/drivers/media/rc/ttusbir.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20938069fSSean Young /*
30938069fSSean Young  * TechnoTrend USB IR Receiver
40938069fSSean Young  *
50938069fSSean Young  * Copyright (C) 2012 Sean Young <sean@mess.org>
60938069fSSean Young  */
70938069fSSean Young 
80938069fSSean Young #include <linux/module.h>
90938069fSSean Young #include <linux/usb.h>
100938069fSSean Young #include <linux/usb/input.h>
110938069fSSean Young #include <linux/slab.h>
120938069fSSean Young #include <linux/leds.h>
130938069fSSean Young #include <media/rc-core.h>
140938069fSSean Young 
150938069fSSean Young #define DRIVER_NAME	"ttusbir"
160938069fSSean Young #define DRIVER_DESC	"TechnoTrend USB IR Receiver"
170938069fSSean Young /*
180938069fSSean Young  * The Windows driver uses 8 URBS, the original lirc drivers has a
190938069fSSean Young  * configurable amount (2 default, 4 max). This device generates about 125
200938069fSSean Young  * messages per second (!), whether IR is idle or not.
210938069fSSean Young  */
220938069fSSean Young #define NUM_URBS	4
23528222d8SSean Young #define US_PER_BYTE	62
24528222d8SSean Young #define US_PER_BIT	(US_PER_BYTE / 8)
250938069fSSean Young 
260938069fSSean Young struct ttusbir {
270938069fSSean Young 	struct rc_dev *rc;
280938069fSSean Young 	struct device *dev;
290938069fSSean Young 	struct usb_device *udev;
300938069fSSean Young 
310938069fSSean Young 	struct urb *urb[NUM_URBS];
320938069fSSean Young 
330938069fSSean Young 	struct led_classdev led;
340938069fSSean Young 	struct urb *bulk_urb;
350938069fSSean Young 	uint8_t bulk_buffer[5];
360938069fSSean Young 	int bulk_out_endp, iso_in_endp;
370938069fSSean Young 	bool led_on, is_led_on;
380938069fSSean Young 	atomic_t led_complete;
390938069fSSean Young 
400938069fSSean Young 	char phys[64];
410938069fSSean Young };
420938069fSSean Young 
ttusbir_brightness_get(struct led_classdev * led_dev)430938069fSSean Young static enum led_brightness ttusbir_brightness_get(struct led_classdev *led_dev)
440938069fSSean Young {
450938069fSSean Young 	struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
460938069fSSean Young 
470938069fSSean Young 	return tt->led_on ? LED_FULL : LED_OFF;
480938069fSSean Young }
490938069fSSean Young 
ttusbir_set_led(struct ttusbir * tt)500938069fSSean Young static void ttusbir_set_led(struct ttusbir *tt)
510938069fSSean Young {
520938069fSSean Young 	int ret;
530938069fSSean Young 
540938069fSSean Young 	smp_mb();
550938069fSSean Young 
563404cb5cSSean Young 	if (tt->led_on != tt->is_led_on && tt->udev &&
570938069fSSean Young 				atomic_add_unless(&tt->led_complete, 1, 1)) {
580938069fSSean Young 		tt->bulk_buffer[4] = tt->is_led_on = tt->led_on;
590938069fSSean Young 		ret = usb_submit_urb(tt->bulk_urb, GFP_ATOMIC);
603404cb5cSSean Young 		if (ret) {
610938069fSSean Young 			dev_warn(tt->dev, "failed to submit bulk urb: %d\n",
620938069fSSean Young 									ret);
630938069fSSean Young 			atomic_dec(&tt->led_complete);
640938069fSSean Young 		}
650938069fSSean Young 	}
660938069fSSean Young }
670938069fSSean Young 
ttusbir_brightness_set(struct led_classdev * led_dev,enum led_brightness brightness)680938069fSSean Young static void ttusbir_brightness_set(struct led_classdev *led_dev, enum
690938069fSSean Young 						led_brightness brightness)
700938069fSSean Young {
710938069fSSean Young 	struct ttusbir *tt = container_of(led_dev, struct ttusbir, led);
720938069fSSean Young 
730938069fSSean Young 	tt->led_on = brightness != LED_OFF;
740938069fSSean Young 
750938069fSSean Young 	ttusbir_set_led(tt);
760938069fSSean Young }
770938069fSSean Young 
780938069fSSean Young /*
790938069fSSean Young  * The urb cannot be reused until the urb completes
800938069fSSean Young  */
ttusbir_bulk_complete(struct urb * urb)810938069fSSean Young static void ttusbir_bulk_complete(struct urb *urb)
820938069fSSean Young {
830938069fSSean Young 	struct ttusbir *tt = urb->context;
840938069fSSean Young 
850938069fSSean Young 	atomic_dec(&tt->led_complete);
860938069fSSean Young 
870938069fSSean Young 	switch (urb->status) {
880938069fSSean Young 	case 0:
890938069fSSean Young 		break;
900938069fSSean Young 	case -ECONNRESET:
910938069fSSean Young 	case -ENOENT:
920938069fSSean Young 	case -ESHUTDOWN:
930938069fSSean Young 		return;
940938069fSSean Young 	case -EPIPE:
950938069fSSean Young 	default:
960938069fSSean Young 		dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
970938069fSSean Young 		break;
980938069fSSean Young 	}
990938069fSSean Young 
1000938069fSSean Young 	ttusbir_set_led(tt);
1010938069fSSean Young }
1020938069fSSean Young 
1030938069fSSean Young /*
1040938069fSSean Young  * The data is one bit per sample, a set bit signifying silence and samples
1050938069fSSean Young  * being MSB first. Bit 0 can contain garbage so take it to be whatever
1060938069fSSean Young  * bit 1 is, so we don't have unexpected edges.
1070938069fSSean Young  */
ttusbir_process_ir_data(struct ttusbir * tt,uint8_t * buf)1080938069fSSean Young static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
1090938069fSSean Young {
110183e19f5SSean Young 	struct ir_raw_event rawir = {};
1110938069fSSean Young 	unsigned i, v, b;
112b83bfd1bSSean Young 	bool event = false;
1130938069fSSean Young 
1140938069fSSean Young 	for (i = 0; i < 128; i++) {
1150938069fSSean Young 		v = buf[i] & 0xfe;
1160938069fSSean Young 		switch (v) {
1170938069fSSean Young 		case 0xfe:
1180938069fSSean Young 			rawir.pulse = false;
119528222d8SSean Young 			rawir.duration = US_PER_BYTE;
120b83bfd1bSSean Young 			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
121b83bfd1bSSean Young 				event = true;
1220938069fSSean Young 			break;
1230938069fSSean Young 		case 0:
1240938069fSSean Young 			rawir.pulse = true;
125528222d8SSean Young 			rawir.duration = US_PER_BYTE;
126b83bfd1bSSean Young 			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
127b83bfd1bSSean Young 				event = true;
1280938069fSSean Young 			break;
1290938069fSSean Young 		default:
1300938069fSSean Young 			/* one edge per byte */
1310938069fSSean Young 			if (v & 2) {
1320938069fSSean Young 				b = ffz(v | 1);
1330938069fSSean Young 				rawir.pulse = true;
1340938069fSSean Young 			} else {
1350938069fSSean Young 				b = ffs(v) - 1;
1360938069fSSean Young 				rawir.pulse = false;
1370938069fSSean Young 			}
1380938069fSSean Young 
139528222d8SSean Young 			rawir.duration = US_PER_BIT * (8 - b);
140b83bfd1bSSean Young 			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
141b83bfd1bSSean Young 				event = true;
1420938069fSSean Young 
1430938069fSSean Young 			rawir.pulse = !rawir.pulse;
144528222d8SSean Young 			rawir.duration = US_PER_BIT * b;
145b83bfd1bSSean Young 			if (ir_raw_event_store_with_filter(tt->rc, &rawir))
146b83bfd1bSSean Young 				event = true;
1470938069fSSean Young 			break;
1480938069fSSean Young 		}
1490938069fSSean Young 	}
1500938069fSSean Young 
151b83bfd1bSSean Young 	/* don't wakeup when there's nothing to do */
152b83bfd1bSSean Young 	if (event)
1530938069fSSean Young 		ir_raw_event_handle(tt->rc);
1540938069fSSean Young }
1550938069fSSean Young 
ttusbir_urb_complete(struct urb * urb)1560938069fSSean Young static void ttusbir_urb_complete(struct urb *urb)
1570938069fSSean Young {
1580938069fSSean Young 	struct ttusbir *tt = urb->context;
1590938069fSSean Young 	int rc;
1600938069fSSean Young 
1610938069fSSean Young 	switch (urb->status) {
1620938069fSSean Young 	case 0:
1630938069fSSean Young 		ttusbir_process_ir_data(tt, urb->transfer_buffer);
1640938069fSSean Young 		break;
1650938069fSSean Young 	case -ECONNRESET:
1660938069fSSean Young 	case -ENOENT:
1670938069fSSean Young 	case -ESHUTDOWN:
1680938069fSSean Young 		return;
1690938069fSSean Young 	case -EPIPE:
1700938069fSSean Young 	default:
1710938069fSSean Young 		dev_dbg(tt->dev, "Error: urb status = %d\n", urb->status);
1720938069fSSean Young 		break;
1730938069fSSean Young 	}
1740938069fSSean Young 
1750938069fSSean Young 	rc = usb_submit_urb(urb, GFP_ATOMIC);
1760938069fSSean Young 	if (rc && rc != -ENODEV)
1770938069fSSean Young 		dev_warn(tt->dev, "failed to resubmit urb: %d\n", rc);
1780938069fSSean Young }
1790938069fSSean Young 
ttusbir_probe(struct usb_interface * intf,const struct usb_device_id * id)1804c62e976SGreg Kroah-Hartman static int ttusbir_probe(struct usb_interface *intf,
1810938069fSSean Young 			 const struct usb_device_id *id)
1820938069fSSean Young {
1830938069fSSean Young 	struct ttusbir *tt;
1840938069fSSean Young 	struct usb_interface_descriptor *idesc;
1850938069fSSean Young 	struct usb_endpoint_descriptor *desc;
1860938069fSSean Young 	struct rc_dev *rc;
1870938069fSSean Young 	int i, j, ret;
1880938069fSSean Young 	int altsetting = -1;
1890938069fSSean Young 
1900938069fSSean Young 	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
1910f7499fdSAndi Shyti 	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
1920938069fSSean Young 	if (!tt || !rc) {
1930938069fSSean Young 		ret = -ENOMEM;
1940938069fSSean Young 		goto out;
1950938069fSSean Young 	}
1960938069fSSean Young 
1970938069fSSean Young 	/* find the correct alt setting */
1980938069fSSean Young 	for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
1991e801adcSSean Young 		int max_packet, bulk_out_endp = -1, iso_in_endp = -1;
2000938069fSSean Young 
2010938069fSSean Young 		idesc = &intf->altsetting[i].desc;
2020938069fSSean Young 
2030938069fSSean Young 		for (j = 0; j < idesc->bNumEndpoints; j++) {
2040938069fSSean Young 			desc = &intf->altsetting[i].endpoint[j].desc;
2051e801adcSSean Young 			max_packet = le16_to_cpu(desc->wMaxPacketSize);
2060938069fSSean Young 			if (usb_endpoint_dir_in(desc) &&
2070938069fSSean Young 					usb_endpoint_xfer_isoc(desc) &&
2081e801adcSSean Young 					max_packet == 0x10)
2090938069fSSean Young 				iso_in_endp = j;
2100938069fSSean Young 			else if (usb_endpoint_dir_out(desc) &&
2110938069fSSean Young 					usb_endpoint_xfer_bulk(desc) &&
2121e801adcSSean Young 					max_packet == 0x20)
2130938069fSSean Young 				bulk_out_endp = j;
2140938069fSSean Young 
2150938069fSSean Young 			if (bulk_out_endp != -1 && iso_in_endp != -1) {
2160938069fSSean Young 				tt->bulk_out_endp = bulk_out_endp;
2170938069fSSean Young 				tt->iso_in_endp = iso_in_endp;
2180938069fSSean Young 				altsetting = i;
2190938069fSSean Young 				break;
2200938069fSSean Young 			}
2210938069fSSean Young 		}
2220938069fSSean Young 	}
2230938069fSSean Young 
2240938069fSSean Young 	if (altsetting == -1) {
2250938069fSSean Young 		dev_err(&intf->dev, "cannot find expected altsetting\n");
2260938069fSSean Young 		ret = -ENODEV;
2270938069fSSean Young 		goto out;
2280938069fSSean Young 	}
2290938069fSSean Young 
2300938069fSSean Young 	tt->dev = &intf->dev;
2310938069fSSean Young 	tt->udev = interface_to_usbdev(intf);
2320938069fSSean Young 	tt->rc = rc;
2330938069fSSean Young 
2340938069fSSean Young 	ret = usb_set_interface(tt->udev, 0, altsetting);
2350938069fSSean Young 	if (ret)
2360938069fSSean Young 		goto out;
2370938069fSSean Young 
2380938069fSSean Young 	for (i = 0; i < NUM_URBS; i++) {
2390938069fSSean Young 		struct urb *urb = usb_alloc_urb(8, GFP_KERNEL);
2400938069fSSean Young 		void *buffer;
2410938069fSSean Young 
2420938069fSSean Young 		if (!urb) {
2430938069fSSean Young 			ret = -ENOMEM;
2440938069fSSean Young 			goto out;
2450938069fSSean Young 		}
2460938069fSSean Young 
2470938069fSSean Young 		urb->dev = tt->udev;
2480938069fSSean Young 		urb->context = tt;
2490938069fSSean Young 		urb->pipe = usb_rcvisocpipe(tt->udev, tt->iso_in_endp);
2500938069fSSean Young 		urb->interval = 1;
2510938069fSSean Young 		buffer = usb_alloc_coherent(tt->udev, 128, GFP_KERNEL,
2520938069fSSean Young 						&urb->transfer_dma);
2530938069fSSean Young 		if (!buffer) {
2540938069fSSean Young 			usb_free_urb(urb);
2550938069fSSean Young 			ret = -ENOMEM;
2560938069fSSean Young 			goto out;
2570938069fSSean Young 		}
2580938069fSSean Young 		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP | URB_ISO_ASAP;
2590938069fSSean Young 		urb->transfer_buffer = buffer;
2600938069fSSean Young 		urb->complete = ttusbir_urb_complete;
2610938069fSSean Young 		urb->number_of_packets = 8;
2620938069fSSean Young 		urb->transfer_buffer_length = 128;
2630938069fSSean Young 
2640938069fSSean Young 		for (j = 0; j < 8; j++) {
2650938069fSSean Young 			urb->iso_frame_desc[j].offset = j * 16;
2660938069fSSean Young 			urb->iso_frame_desc[j].length = 16;
2670938069fSSean Young 		}
2680938069fSSean Young 
2690938069fSSean Young 		tt->urb[i] = urb;
2700938069fSSean Young 	}
2710938069fSSean Young 
2720938069fSSean Young 	tt->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
2730938069fSSean Young 	if (!tt->bulk_urb) {
2740938069fSSean Young 		ret = -ENOMEM;
2750938069fSSean Young 		goto out;
2760938069fSSean Young 	}
2770938069fSSean Young 
2780938069fSSean Young 	tt->bulk_buffer[0] = 0xaa;
2790938069fSSean Young 	tt->bulk_buffer[1] = 0x01;
2800938069fSSean Young 	tt->bulk_buffer[2] = 0x05;
2810938069fSSean Young 	tt->bulk_buffer[3] = 0x01;
2820938069fSSean Young 
2830938069fSSean Young 	usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
2840938069fSSean Young 		tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
2850938069fSSean Young 						ttusbir_bulk_complete, tt);
2860938069fSSean Young 
2873404cb5cSSean Young 	tt->led.name = "ttusbir:green:power";
2885704e76cSSean Young 	tt->led.default_trigger = "rc-feedback";
2890938069fSSean Young 	tt->led.brightness_set = ttusbir_brightness_set;
2900938069fSSean Young 	tt->led.brightness_get = ttusbir_brightness_get;
2910938069fSSean Young 	tt->is_led_on = tt->led_on = true;
2920938069fSSean Young 	atomic_set(&tt->led_complete, 0);
2930938069fSSean Young 	ret = led_classdev_register(&intf->dev, &tt->led);
2940938069fSSean Young 	if (ret)
2950938069fSSean Young 		goto out;
2960938069fSSean Young 
2970938069fSSean Young 	usb_make_path(tt->udev, tt->phys, sizeof(tt->phys));
2980938069fSSean Young 
299518f4b26SSean Young 	rc->device_name = DRIVER_DESC;
3000938069fSSean Young 	rc->input_phys = tt->phys;
3010938069fSSean Young 	usb_to_input_id(tt->udev, &rc->input_id);
3020938069fSSean Young 	rc->dev.parent = &intf->dev;
3036d741bfeSSean Young 	rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
3040938069fSSean Young 	rc->priv = tt;
3050938069fSSean Young 	rc->driver_name = DRIVER_NAME;
3060938069fSSean Young 	rc->map_name = RC_MAP_TT_1500;
30756a6036cSSean Young 	rc->min_timeout = 1;
30856a6036cSSean Young 	rc->timeout = IR_DEFAULT_TIMEOUT;
30956a6036cSSean Young 	rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
31056a6036cSSean Young 
3110938069fSSean Young 	/*
312528222d8SSean Young 	 * The precision is US_PER_BIT, but since every 8th bit can be
313528222d8SSean Young 	 * overwritten with garbage the accuracy is at best 2 * US_PER_BIT.
3140938069fSSean Young 	 */
315528222d8SSean Young 	rc->rx_resolution = 2 * US_PER_BIT;
3160938069fSSean Young 
3170938069fSSean Young 	ret = rc_register_device(rc);
3180938069fSSean Young 	if (ret) {
3190938069fSSean Young 		dev_err(&intf->dev, "failed to register rc device %d\n", ret);
3200938069fSSean Young 		goto out2;
3210938069fSSean Young 	}
3220938069fSSean Young 
3230938069fSSean Young 	usb_set_intfdata(intf, tt);
3240938069fSSean Young 
3250938069fSSean Young 	for (i = 0; i < NUM_URBS; i++) {
3260938069fSSean Young 		ret = usb_submit_urb(tt->urb[i], GFP_KERNEL);
3270938069fSSean Young 		if (ret) {
3280938069fSSean Young 			dev_err(tt->dev, "failed to submit urb %d\n", ret);
3290938069fSSean Young 			goto out3;
3300938069fSSean Young 		}
3310938069fSSean Young 	}
3320938069fSSean Young 
3330938069fSSean Young 	return 0;
3340938069fSSean Young out3:
3350938069fSSean Young 	rc_unregister_device(rc);
336a9bd87c2SJiri Slaby 	rc = NULL;
3370938069fSSean Young out2:
3380938069fSSean Young 	led_classdev_unregister(&tt->led);
3390938069fSSean Young out:
3400938069fSSean Young 	if (tt) {
3410938069fSSean Young 		for (i = 0; i < NUM_URBS && tt->urb[i]; i++) {
3420938069fSSean Young 			struct urb *urb = tt->urb[i];
3430938069fSSean Young 
3440938069fSSean Young 			usb_kill_urb(urb);
3450938069fSSean Young 			usb_free_coherent(tt->udev, 128, urb->transfer_buffer,
3460938069fSSean Young 							urb->transfer_dma);
3470938069fSSean Young 			usb_free_urb(urb);
3480938069fSSean Young 		}
3490938069fSSean Young 		usb_kill_urb(tt->bulk_urb);
3500938069fSSean Young 		usb_free_urb(tt->bulk_urb);
3510938069fSSean Young 		kfree(tt);
3520938069fSSean Young 	}
3530938069fSSean Young 	rc_free_device(rc);
3540938069fSSean Young 
3550938069fSSean Young 	return ret;
3560938069fSSean Young }
3570938069fSSean Young 
ttusbir_disconnect(struct usb_interface * intf)3584c62e976SGreg Kroah-Hartman static void ttusbir_disconnect(struct usb_interface *intf)
3590938069fSSean Young {
3600938069fSSean Young 	struct ttusbir *tt = usb_get_intfdata(intf);
3613404cb5cSSean Young 	struct usb_device *udev = tt->udev;
3620938069fSSean Young 	int i;
3630938069fSSean Young 
3643404cb5cSSean Young 	tt->udev = NULL;
3653404cb5cSSean Young 
3660938069fSSean Young 	rc_unregister_device(tt->rc);
3670938069fSSean Young 	led_classdev_unregister(&tt->led);
3680938069fSSean Young 	for (i = 0; i < NUM_URBS; i++) {
3690938069fSSean Young 		usb_kill_urb(tt->urb[i]);
3703404cb5cSSean Young 		usb_free_coherent(udev, 128, tt->urb[i]->transfer_buffer,
3710938069fSSean Young 						tt->urb[i]->transfer_dma);
3720938069fSSean Young 		usb_free_urb(tt->urb[i]);
3730938069fSSean Young 	}
3740938069fSSean Young 	usb_kill_urb(tt->bulk_urb);
3750938069fSSean Young 	usb_free_urb(tt->bulk_urb);
3760938069fSSean Young 	usb_set_intfdata(intf, NULL);
3770938069fSSean Young 	kfree(tt);
3780938069fSSean Young }
3790938069fSSean Young 
ttusbir_suspend(struct usb_interface * intf,pm_message_t message)3803404cb5cSSean Young static int ttusbir_suspend(struct usb_interface *intf, pm_message_t message)
3813404cb5cSSean Young {
3823404cb5cSSean Young 	struct ttusbir *tt = usb_get_intfdata(intf);
3833404cb5cSSean Young 	int i;
3843404cb5cSSean Young 
3853404cb5cSSean Young 	for (i = 0; i < NUM_URBS; i++)
3863404cb5cSSean Young 		usb_kill_urb(tt->urb[i]);
3873404cb5cSSean Young 
3883404cb5cSSean Young 	led_classdev_suspend(&tt->led);
3893404cb5cSSean Young 	usb_kill_urb(tt->bulk_urb);
3903404cb5cSSean Young 
3913404cb5cSSean Young 	return 0;
3923404cb5cSSean Young }
3933404cb5cSSean Young 
ttusbir_resume(struct usb_interface * intf)3943404cb5cSSean Young static int ttusbir_resume(struct usb_interface *intf)
3953404cb5cSSean Young {
3963404cb5cSSean Young 	struct ttusbir *tt = usb_get_intfdata(intf);
3973404cb5cSSean Young 	int i, rc;
3983404cb5cSSean Young 
3993404cb5cSSean Young 	tt->is_led_on = true;
400d2008b56SSean Young 	led_classdev_resume(&tt->led);
4013404cb5cSSean Young 
4023404cb5cSSean Young 	for (i = 0; i < NUM_URBS; i++) {
403*d040f0e7SOliver Neukum 		rc = usb_submit_urb(tt->urb[i], GFP_NOIO);
4043404cb5cSSean Young 		if (rc) {
4053404cb5cSSean Young 			dev_warn(tt->dev, "failed to submit urb: %d\n", rc);
4063404cb5cSSean Young 			break;
4073404cb5cSSean Young 		}
4083404cb5cSSean Young 	}
4093404cb5cSSean Young 
4103404cb5cSSean Young 	return rc;
4113404cb5cSSean Young }
4123404cb5cSSean Young 
4130938069fSSean Young static const struct usb_device_id ttusbir_table[] = {
4140938069fSSean Young 	{ USB_DEVICE(0x0b48, 0x2003) },
4150938069fSSean Young 	{ }
4160938069fSSean Young };
4170938069fSSean Young 
4180938069fSSean Young static struct usb_driver ttusbir_driver = {
4190938069fSSean Young 	.name = DRIVER_NAME,
4200938069fSSean Young 	.id_table = ttusbir_table,
4210938069fSSean Young 	.probe = ttusbir_probe,
4223404cb5cSSean Young 	.suspend = ttusbir_suspend,
4233404cb5cSSean Young 	.resume = ttusbir_resume,
4243404cb5cSSean Young 	.reset_resume = ttusbir_resume,
4254c62e976SGreg Kroah-Hartman 	.disconnect = ttusbir_disconnect,
4260938069fSSean Young };
4270938069fSSean Young 
4280938069fSSean Young module_usb_driver(ttusbir_driver);
4290938069fSSean Young 
4300938069fSSean Young MODULE_DESCRIPTION(DRIVER_DESC);
4310938069fSSean Young MODULE_AUTHOR("Sean Young <sean@mess.org>");
4320938069fSSean Young MODULE_LICENSE("GPL");
4330938069fSSean Young MODULE_DEVICE_TABLE(usb, ttusbir_table);
4340938069fSSean Young 
435