litmus-rt-budgetable-locks.git/.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogblamecommitdiffstats
path: root/drivers/usb/misc/yurex.c
blob: 6d9fd5f649036e8fb47c39eaeffa26f856724e99 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                   



                                                                 



                         
























                                                          
                                      








                                                                       
                                 
     
                                   
































                                                                             

                                                                    









                                                                       
                                                        

                               

                                            
                                     




                                                                               































                                                                          


                                                                              






                                                        

                                                                                














                                                             

                                                                         




                                                                       

                                                                

                      

                                                             






                                                      
                                                                                 









                                                                                       
                          
                


                                                                    
                 
                           









                                                                

                                                              
                                                                       
                             


                           
                                                              


                                                     
                           
                           

                                             
                                                            
                           
                           





                                                                            
                                                                             














                                                                                 
                                                                 



                                                
                      
                           




                                                                             
                                                                            







                                                                             
                                                            

                                                   
                                                                       




                                                            
                      



                                                            

                                                                      



                                                  
                                 
                                                                

































                                                             
                                                                             













                                                          
                                 













                                                                

                                                                             

























                                                                
                                 


                               




                                               

                                                                               

                              
                    


                            
                                 


                                                                  

                                             


                                             
                                                          
                                                  
                                     
 


                                                   
                                                                            

 

                                                                             


                                   
                            




                                     
                                               
                                 





                                                             
                                                                  









                                                         
                          


































                                                                

                                                                   







                                                                


                                                                   
















                                                  
                                       

  
                                

                      
// SPDX-License-Identifier: GPL-2.0
/*
 * Driver for Meywa-Denki & KAYAC YUREX
 *
 * Copyright (C) 2010 Tomoki Sekiyama (tomoki.sekiyama@gmail.com)
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/hid.h>

#define DRIVER_AUTHOR "Tomoki Sekiyama"
#define DRIVER_DESC "Driver for Meywa-Denki & KAYAC YUREX"

#define YUREX_VENDOR_ID		0x0c45
#define YUREX_PRODUCT_ID	0x1010

#define CMD_ACK		'!'
#define CMD_ANIMATE	'A'
#define CMD_COUNT	'C'
#define CMD_LED		'L'
#define CMD_READ	'R'
#define CMD_SET		'S'
#define CMD_VERSION	'V'
#define CMD_EOF		0x0d
#define CMD_PADDING	0xff

#define YUREX_BUF_SIZE		8
#define YUREX_WRITE_TIMEOUT	(HZ*2)

/* table of devices that work with this driver */
static struct usb_device_id yurex_table[] = {
	{ USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
	{ }					/* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, yurex_table);

#ifdef CONFIG_USB_DYNAMIC_MINORS
#define YUREX_MINOR_BASE	0
#else
#define YUREX_MINOR_BASE	192
#endif

/* Structure to hold all of our device specific stuff */
struct usb_yurex {
	struct usb_device	*udev;
	struct usb_interface	*interface;
	__u8			int_in_endpointAddr;
	struct urb		*urb;		/* URB for interrupt in */
	unsigned char           *int_buffer;	/* buffer for intterupt in */
	struct urb		*cntl_urb;	/* URB for control msg */
	struct usb_ctrlrequest	*cntl_req;	/* req for control msg */
	unsigned char		*cntl_buffer;	/* buffer for control msg */

	struct kref		kref;
	struct mutex		io_mutex;
	struct fasync_struct	*async_queue;
	wait_queue_head_t	waitq;

	spinlock_t		lock;
	__s64			bbu;		/* BBU from device */
};
#define to_yurex_dev(d) container_of(d, struct usb_yurex, kref)

static struct usb_driver yurex_driver;
static const struct file_operations yurex_fops;


static void yurex_control_callback(struct urb *urb)
{
	struct usb_yurex *dev = urb->context;
	int status = urb->status;

	if (status) {
		dev_err(&urb->dev->dev, "%s - control failed: %d\n",
			__func__, status);
		wake_up_interruptible(&dev->waitq);
		return;
	}
	/* on success, sender woken up by CMD_ACK int in, or timeout */
}

static void yurex_delete(struct kref *kref)
{
	struct usb_yurex *dev = to_yurex_dev(kref);

	dev_dbg(&dev->interface->dev, "%s\n", __func__);

	usb_put_dev(dev->udev);
	if (dev->cntl_urb) {
		usb_kill_urb(dev->cntl_urb);
		kfree(dev->cntl_req);
		if (dev->cntl_buffer)
			usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
				dev->cntl_buffer, dev->cntl_urb->transfer_dma);
		usb_free_urb(dev->cntl_urb);
	}
	if (dev->urb) {
		usb_kill_urb(dev->urb);
		if (dev->int_buffer)
			usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
				dev->int_buffer, dev->urb->transfer_dma);
		usb_free_urb(dev->urb);
	}
	kfree(dev);
}

/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with the driver core
 */
static struct usb_class_driver yurex_class = {
	.name =		"yurex%d",
	.fops =		&yurex_fops,
	.minor_base =	YUREX_MINOR_BASE,
};

static void yurex_interrupt(struct urb *urb)
{
	struct usb_yurex *dev = urb->context;
	unsigned char *buf = dev->int_buffer;
	int status = urb->status;
	unsigned long flags;
	int retval, i;

	switch (status) {
	case 0: /*success*/
		break;
	case -EOVERFLOW:
		dev_err(&dev->interface->dev,
			"%s - overflow with length %d, actual length is %d\n",
			__func__, YUREX_BUF_SIZE, dev->urb->actual_length);
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
	case -EILSEQ:
		/* The device is terminated, clean up */
		return;
	default:
		dev_err(&dev->interface->dev,
			"%s - unknown status received: %d\n", __func__, status);
		goto exit;
	}

	/* handle received message */
	switch (buf[0]) {
	case CMD_COUNT:
	case CMD_READ:
		if (buf[6] == CMD_EOF) {
			spin_lock_irqsave(&dev->lock, flags);
			dev->bbu = 0;
			for (i = 1; i < 6; i++) {
				dev->bbu += buf[i];
				if (i != 5)
					dev->bbu <<= 8;
			}
			dev_dbg(&dev->interface->dev, "%s count: %lld\n",
				__func__, dev->bbu);
			spin_unlock_irqrestore(&dev->lock, flags);

			kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
		}
		else
			dev_dbg(&dev->interface->dev,
				"data format error - no EOF\n");
		break;
	case CMD_ACK:
		dev_dbg(&dev->interface->dev, "%s ack: %c\n",
			__func__, buf[1]);
		wake_up_interruptible(&dev->waitq);
		break;
	}

exit:
	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
	if (retval) {
		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
			__func__, retval);
	}
}

static int yurex_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
	struct usb_yurex *dev;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	int retval = -ENOMEM;
	DEFINE_WAIT(wait);
	int res;

	/* allocate memory for our device state and initialize it */
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		goto error;
	kref_init(&dev->kref);
	mutex_init(&dev->io_mutex);
	spin_lock_init(&dev->lock);
	init_waitqueue_head(&dev->waitq);

	dev->udev = usb_get_dev(interface_to_usbdev(interface));
	dev->interface = interface;

	/* set up the endpoint information */