⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 otg_hub.c

📁 philips公司ISP1362 USB OTG控制芯片的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * USB hub driver.
 *
 * (C) Copyright 1999 Linus Torvalds
 * (C) Copyright 1999 Johannes Erdfelt
 * (C) Copyright 1999 Gregory P. Smith
 * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
 *
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_USB_DEBUG
	#define DEBUG
#else
	#undef DEBUG
#endif
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>

#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>

#include "otg_hub.h"

/* Wakes up khubd */
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_MUTEX(usb_address0_sem);

static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */

static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static int khubd_pid = 0;			/* PID of khubd */
static DECLARE_COMPLETION(khubd_exited);

#ifdef	DEBUG
static inline char *portspeed (int portstatus)
{
	if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
    		return "480 Mb/s";
	else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
		return "1.5 Mb/s";
	else
		return "12 Mb/s";
}
#endif


/*-----------------------------------------------------------
 * Additional Functions for OTG-HUB 
 * ---------------------------------------------------------*/

/*_ Global variables */
static struct usb_driver * old_hub_driver = NULL;	/* driver that comes with USB CORE */
extern	struct list_head * usb_driver_get_list(void);	/* Exporting this function from USB CORE 
							   Requires CONFIG_PROC_FS support */
#define	OTG_HUB_RESET_TIME	50
#define	USB_OTG_HUB_SET_TIMEOUT	3

LIST_HEAD(otg_hub_bus_list);

/*-----------------------------------------------------------
 * This function registers the OTG BUS to the OTG HUB
 * returns 0 on success and -ve value on failure
 * puts the OTG bus in the linked list
 * ---------------------------------------------------------*/
int	otg_hub_register_otg_bus(struct usb_otg_bus *otg_bus) {

	list_add(&otg_bus->bus_list, &otg_hub_bus_list);

	return 0;
}

/*-----------------------------------------------------------
 * This function registers the OTG BUS to the OTG HUB
 * removes the OTG bus from the linked list
 * ---------------------------------------------------------*/
void 	otg_hub_deregister_otg_bus(struct usb_otg_bus *otg_bus) {

	list_del(&otg_bus->bus_list);
}

/*----------------------------------------------------------------
 * Get the OTG Bus data structure from the USB Bus data structure
 * this function returns the OTG-BUS for the corresponding
 * USB-BUS if it is present in the OTG-BUS list
 * otherwise returns NULL
 * --------------------------------------------------------------*/
struct usb_otg_bus *otg_hub_get_otg_bus(struct usb_bus *bus) {
	struct list_head *tmp;

	tmp = otg_hub_bus_list.next;
	while (tmp != &otg_hub_bus_list) {
		struct usb_otg_bus *otg_bus = list_entry(tmp,struct usb_otg_bus, bus_list);

		if(otg_bus->usb_bus == bus)	{
				return otg_bus;
		}
		tmp = tmp->next;
	}

	return NULL;
}


/*--------------------------------------------------
 * Set FEATURE function whihc internally calls the 
 * USB control message with the reuired parameters
 * -----------------------------------------------*/
int	otg_hub_set_otg_feature(struct usb_device *dev, int	feature) {

	return usb_control_msg(	dev, usb_sndctrlpipe(dev,0), 
				USB_REQ_SET_FEATURE, 0, feature, 
				0, NULL, 0, HZ * USB_OTG_HUB_SET_TIMEOUT);
}

/*-----------------------------------------------------
 * This function checks the device configuration and
 * calls the OTG enumeration function. If successful
 * calls the USB new_device function
 * ---------------------------------------------------*/
int otg_hub_new_device(struct usb_device *otg_dev, int port)
{
	int err;
	struct usb_device *dev = NULL;
	struct usb_otg_bus *hub_bus = NULL;


	hub_bus = otg_hub_get_otg_bus(otg_dev->bus);

	/* If the new device is connected on the root port and if 
	 * the HCD OTG is enabled */
	if((otg_dev->parent) && (otg_dev->parent == otg_dev->bus->root_hub) && hub_bus) {

		dev = usb_alloc_dev(otg_dev->bus->root_hub, otg_dev->bus);

		if(dev == NULL)	return -1;

		/* Replace the device with the new data structure */
//		memcpy(dev, otg_dev, sizeof(struct usb_device));

		otg_dev->parent->children[port] = dev;

		dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
		dev->devnum = 0;

		dev->parent = otg_dev->parent;
		
		/* USB v1.1 5.5.3 */
		/* We read the first 8 bytes from the device descriptor to get to */
		/*  the bMaxPacketSize0 field. Then we set the maximum packet size */
		/*  for the control pipe, and retrieve the rest */
		dev->epmaxpacketin [0] = 8;
		dev->epmaxpacketout[0] = 8;

		wait_ms(10);	/* Let the SET_ADDRESS settle */
	
		/* Address is not set yet, all communication is on default pipe */
		dev->devnum = 0;

		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
		if (err < 8) {
			if (err < 0)
				err("USB device not responding, giving up (error=%d)", err);
			else
				err("USB device descriptor short read (expected %i, got %i)", 8, err);
			goto error;
		}

		dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
		dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
	
		err = usb_get_device_descriptor(dev);
		if (err < (signed)sizeof(dev->descriptor)) {
			if (err < 0)
				err("unable to get device descriptor (error=%d)", err);
			else
				err("USB device descriptor short read (expected %Zi, got %i)",
					sizeof(dev->descriptor), err);
		
			goto error;
		}
	
		err = usb_get_configuration(dev);
		if (err < 0) {
			err("unable to get device %d configuration (error=%d)",
				dev->devnum, err);
			goto error;
		}
	
		if(hub_bus->otg_new_device) {
			err = hub_bus->otg_new_device(hub_bus->otg_priv,dev);
			if (err < 0) {
//				err("unable to do OTG enumeration for %d dev , err = %d\n", dev->devnum, err);
				goto error;
			}
		}

		usb_free_dev(dev);

		/* Replace the original device structure */
		otg_dev->parent->children[port] = otg_dev;
	}

	/* Try to enumerate fresh */
	return usb_new_device(otg_dev);

error:
	clear_bit(otg_dev->devnum, &otg_dev->bus->devmap.devicemap);
	otg_dev->devnum = -1;
	otg_dev->parent->children[port] = otg_dev;
	usb_free_dev(dev);

	return 1;
}

/*----------End OTG-HUB new functions ---------------------------------*/

/* USB 2.0 spec Section 11.24.4.5 */
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
		USB_DT_HUB << 8, 0, data, size, HZ);
}

/*
 * USB 2.0 spec Section 11.24.2.1
 */
static int usb_clear_hub_feature(struct usb_device *dev, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
}

/*
 * USB 2.0 spec Section 11.24.2.2
 * BUG: doesn't handle port indicator selector in high byte of wIndex
 */
static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}

/*
 * USB 2.0 spec Section 11.24.2.13
 * BUG: doesn't handle port indicator selector in high byte of wIndex
 */
static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
{
	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}

/*
 * USB 2.0 spec Section 11.24.2.6
 */
static int usb_get_hub_status(struct usb_device *dev, void *data)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
		data, sizeof(struct usb_hub_status), HZ);
}

/*
 * USB 2.0 spec Section 11.24.2.7
 */
static int usb_get_port_status(struct usb_device *dev, int port, void *data)
{
	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
		data, sizeof(struct usb_hub_status), HZ);
}

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = (struct usb_hub *)urb->context;
	unsigned long flags;

	/* Cause a hub reset after 10 consecutive errors */
	if (urb->status) {
		if (urb->status == -ENOENT)
			return;

		dbg("nonzero status in irq %d", urb->status);

		if ((++hub->nerrors < 10) || hub->error)
			return;

		hub->error = urb->status;
	}

	hub->nerrors = 0;

	/* Something happened, let khubd figure it out */
	spin_lock_irqsave(&hub_event_lock, flags);
	if (list_empty(&hub->event_list)) {
		list_add(&hub->event_list, &hub_event_list);
		wake_up(&khubd_wait);
	}
	spin_unlock_irqrestore(&hub_event_lock, flags);
}

static void usb_hub_power_on(struct usb_hub *hub)
{
	int i;

	/* Enable power to the ports */
	dbg("enabling power on all ports");
	for (i = 0; i < hub->descriptor->bNbrPorts; i++)
		usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER);

	/* Wait for power to be enabled */
	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
}

static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
{
	struct usb_device *dev = hub->dev;
	struct usb_hub_status hubstatus;
	char portstr[USB_MAXCHILDREN + 1];
	unsigned int pipe;
	int i, maxp, ret;

	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
	if (!hub->descriptor) {
		err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
		return -1;
	}

	/* Request the entire hub descriptor. */
	ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
		/* <hub->descriptor> is large enough for a hub with 127 ports;
		 * the hub can/will return fewer bytes here. */
	if (ret < 0) {
		err("Unable to get hub descriptor (err = %d)", ret);
		kfree(hub->descriptor);
		return -1;
	}

	dev->maxchild = hub->descriptor->bNbrPorts;
	info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");

	le16_to_cpus(&hub->descriptor->wHubCharacteristics);

	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
		dbg("part of a compound device");
	else
		dbg("standalone hub");

	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
		case 0x00:
			dbg("ganged power switching");
			break;
		case 0x01:
			dbg("individual port power switching");
			break;
		case 0x02:
		case 0x03:
			dbg("unknown reserved power switching mode");
			break;
	}

	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
		case 0x00:
			dbg("global over-current protection");
			break;
		case 0x08:
			dbg("individual port over-current protection");
			break;
		case 0x10:
		case 0x18:
			dbg("no over-current protection");
                        break;
	}

	switch (dev->descriptor.bDeviceProtocol) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -