Hi Brad,
MPC850 host driver Patch 2.
m8xxhci_rh.c is the virtual root hub code.
- Roman
--- mpc850p1/m8xxhci.c Wed Mar 14 10:27:13 2001
+++ mpc850p2/m8xxhci.c Wed Mar 14 10:41:25 2001
@@ -111,6 +111,7 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
+#include "hub.h"
#include <asm/io.h>
#include <asm/8xx_immap.h>
@@ -396,14 +397,24 @@
BYTES_PER_USB_FRAME /* bulk remaining% */
};
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void * urb;
+ void * int_addr;
+ int send;
+ int interval;
+ struct timer_list rh_int_timer;
+};
+
/*
* this doesn't really need to be a structure, since we can only have
* one mcp usb controller, but it makes things more tidy...
*/
struct m8xxhci_private {
struct usb_bus *bus;
- struct m8xxhci_device *root_hub; /* Root hub device descriptor.. */
-
+ struct virt_root_hub rh;
+
epb_t *epbptr[4]; /* epb ptr */
cbd_t *rbase; /* rx ring bd ptr */
cbd_t *tbase; /* tx ring bd ptr */
@@ -507,7 +518,7 @@
static struct m8xxhci_device *add_local_dev(struct usb_device *usb_dev);
static void assert_resume(int disable);
-static void assert_reset(int disable);
+static void assert_reset(void);
/* debug */
static void dump_tx_state(void);
@@ -515,6 +526,8 @@
static void dump_rx_bds(char *str);
static void dump_state(int stats, int rx, int tx);
+static int bus_res = 1;
+#include "m8xxhci_rh.c"
/* ---- */
@@ -2349,9 +2362,7 @@
m8xxhci_events |= EV_RESET;
- if (waitqueue_active(&m8xxhci_configure)) {
- wake_up(&m8xxhci_configure);
- }
+ bus_res = 1;
}
}
@@ -2840,21 +2851,6 @@
}
}
-static void
-dump_root_hub(void)
-{
- struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
- int i;
-
- printk("hp->root_hub %p, hp->root_hub->usb %p\n",
- hp->root_hub, hp->root_hub->usb);
-
- for (i = 0; i < USB_MAXCHILDREN; i++) {
- if (hp->root_hub->usb->children[i])
- printk("children[%d]=%p\n",
- i, hp->root_hub->usb->children[i]);
- }
-}
/*
* De-allocate all resources..
@@ -2866,349 +2862,6 @@
kfree(m8xxhci);
}
-/* our one and only USB port has gone away */
-static void
-m8xxhci_disconnect_device(void)
-{
- struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
- int i;
-
-#ifdef DEBUG_CHECKS
- if (m8xxhci_debug) {
- printk("m8xxhci_disconnect_device()\n");
- dump_root_hub();
- }
-#endif
-
- /* loose all the children */
- for (i = 0; i < USB_MAXCHILDREN; i++)
- if (hp->root_hub->usb->children[i])
- usb_disconnect(&hp->root_hub->usb->children[i]);
-
- /* loose the device itself */
- usb_disconnect(&hp->root_hub->usb);
-
- hp->root_hub = 0;
- hp->bus->root_hub = 0;
-}
-
-/* something is connected to our one and only USB port */
-static void
-m8xxhci_connect_device(void)
-{
- struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
- struct usb_device *usb_dev;
- struct m8xxhci_device *dev;
-
- log_event(1, "m8xxhci_connect_device", 0);
- if (m8xxhci_verbose) printk("m8xxhci_connect_device()\n");
-
- /* allocate root of tree */
- usb_dev = usb_alloc_dev(NULL, hp->bus);
- if (!usb_dev) {
- err("m8xxhci: couldn't allocate usb_device");
- return;
- }
-
- /* allocate local device info */
- dev = add_local_dev(usb_dev);
- if (!dev) {
- usb_free_dev(usb_dev);
- err("m8xxhci: couldn't allocate internal device");
- return;
- }
-
- /* keep track of directly connected device (most likely a hub) */
- hp->root_hub = usb_to_m8xxhci(usb_dev);
-
- usb_dev->bus = hp->bus;
- hp->bus->root_hub = usb_dev;
-
-// usb_init_root_hub(usb_dev);
-
- usb_dev->maxchild = USB_MAXCHILDREN;
-
- /* assign it a number */
- usb_connect(usb_dev);
-
- /* wait for powerup */
- wait_ms(200);
-
- /* query it */
- usb_new_device(usb_dev);
-}
-
-static int
-m8xxhci_query_device(void)
-{
- int devnum, endpoint, status;
- unsigned long flags;
- struct m8xxhci_qe *qe;
- struct usb_device dd, *dev;
- static unsigned char cmd[8] = { 0x80, 0x06, 0, 1, 0, 0, 8, 0 };
- static unsigned char data[64];
-
- log_event(2, "m8xxhci_query_device", 0);
- if (0) printk("m8xxhci_query_device()\n");
-
- memset((char *)&dd, 0, sizeof(dd));
-
- /* query the root hub's only child */
- if (m8xxhci_ptr->root_hub) {
- dev = m8xxhci_to_usb(m8xxhci_ptr->root_hub);
- } else {
- dev = ⅆ
- }
-
- if (0) printk("m8xxhci_query_device() root_hub %p, dev %p, dd %p\n",
- m8xxhci_ptr->root_hub, dev, &dd);
-
- endpoint = 0;
- devnum = 0;
-
- if (dev->devnum >= 0)
- devnum = dev->devnum;
-
- if (0) printk("hub devnum %d, using devnum %d\n", dev->devnum, devnum);
-
- /* build queue element */
- qe = allocate_qe((struct m8xxhci_device *)0, Q_CTRL);
- if (qe == 0) {
- return -1;
- }
-
- log_event(1, "query qe", (int)qe);
-
- qe->dev = dev;
- qe->pipe = usb_rcvdefctrl(dev);
- qe->devnum = devnum;
- qe->endpoint = endpoint;
- qe->cmd = cmd;
- qe->data = data;
- qe->data_len = 8;
- qe->qstate = QS_SETUP;
- qe->status = 1;
- qe->urb = 0;
-
- /* place qe on queue */
- spin_lock_irqsave(&queue_lock, flags);
- enqueue_qe(qe, Q_CTRL);
- spin_unlock_irqrestore(&queue_lock, flags);
-
-#if 0
- /* start working */
- run_queues();
-#endif
-
- wait_for_qe(qe);
-
- status = qe->status;
-
- log_event(1, "m8xxhci_query_device done status", status);
- if (0) printk("m8xxhci_query_device() done status %d\n", status);
-
- deallocate_qe(qe);
-
- return status;
-}
-
-static void
-m8xxhci_event(int what)
-{
- struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
-
- log_event(2, "m8xxhci_event what", what);
- if (0) printk("m8xxhci_event() what=%d\n", what);
-
- if ((what & EV_QUERY)) {
- switch (hp->driver_state) {
- case DS_FIND_DEVICE:
- assert_reset(0);
- if (m8xxhci_query_device() == 0) {
- hp->driver_state = DS_READY;
- log_event(1, "device found", 0);
- printk("m8xxhci: device found!\n");
- m8xxhci_connect_device();
- }
- break;
- case DS_READY:
- if (m8xxhci_query_device()) {
- log_event(1, "device missing", 0);
- hp->driver_state = DS_MISSING;
- }
- break;
- case DS_MISSING:
- if (m8xxhci_query_device() == 0) {
- log_event(1, "device found again", 0);
- hp->driver_state = DS_READY;
- } else {
- log_event(1, "device lost", 0);
- printk("m8xxhci: device lost\n");
-#if 0
- dump_events();
-#endif
- m8xxhci_disconnect_device();
- hp->driver_state = DS_FIND_DEVICE;
- }
- break;
- }
- }
-
-#if 0
- /* only notice going idle */
- if (!(what & EV_IDLE))
- return;
-
- m8xxhci_connect_device();
-
- /* allow USB RESET condition interrupts again */
- if (0)
- {
- volatile immap_t *immap;
- volatile usbregs_t *usbregs;
-
- immap = (immap_t *)IMAP_ADDR;
- usbregs = (usbregs_t *)&immap->im_cpm.cp_scc[0];
-
- usbregs->usb_usber = BER_RESET | BER_IDLE;
- usbregs->usb_usbmr |= BER_RESET | BER_IDLE;
- mb();
- if (1) printk("usbmr reset 0x%x\n", usbregs->usb_usbmr);
- }
-#endif
-}
-
-static int
-m8xxhci_thread(void *__hub)
-{
- volatile immap_t *immap;
- volatile usbregs_t *usbregs;
- volatile struct m8xxhci_private *hp = m8xxhci_ptr;
-
- immap = (immap_t *)IMAP_ADDR;
- usbregs = (usbregs_t *)&immap->im_cpm.cp_scc[0];
-
- if (m8xxhci_verbose)
- printk("m8xxhci: control thread starting\n");
-
- /*
- * This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- lock_kernel();
- exit_files(current);
- daemonize();
- unlock_kernel();
-
- /* Setup a nice name */
- strcpy(current->comm, "m8xxhci-control");
-
- for(;;) {
- int what;
-
- if ((what = m8xxhci_events)) {
- m8xxhci_events = 0;
- m8xxhci_event(what);
- continue;
- }
-
- interruptible_sleep_on(&m8xxhci_configure);
- }
-
- cleanup_drivers();
-
- m8xxhci_stop_controller();
- release_m8xxhci((struct m8xxhci_private *)hp);
- MOD_DEC_USE_COUNT;
-
- if (m8xxhci_verbose)
- printk("m8xxhci: control thread exiting\n");
-
- return 0;
-}
-
-#if TEST_THREAD /*XXX hack */
-
-static void
-add_pkt_to_tx_ring(void)
-{
- struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
- volatile cbd_t *bdp;
-
- /* always leave 2 bds for a control message */
- if (free_bds() < 3) {
- return;
- }
-
- hp->sof_pkt[0] = 0x99;
- hp->sof_pkt[1] = 0x02;
- hp->sof_pkt[2] = 0x01;
-
- flush_dcache_range(hp->sof_pkt, hp->sof_pkt+3);
-
- bdp = next_bd();
- bdp->cbd_datlen = 20;
- bdp->cbd_bufaddr = __pa(hp->sof_pkt);
- bdp->cbd_sc |= BD_SC_READY | BD_SC_LAST | BD_SC_INTRPT;
-}
-
-static void
-send_marker(int i)
-{
- struct m8xxhci_private *hp = m8xxhci_ptr;
- int bytes;
- unsigned long ticks;
-
- while (1) {
- time_left_in_frame(&bytes);
- ticks = m8xxhci_timer_ticks;
-
- if (bytes < i) {
- lock_tx_ring(hp);
- add_pkt_to_tx_ring();
- m8xxhci_kick_xmit(0);
- unlock_tx_ring(hp);
-
- while (ticks == m8xxhci_timer_ticks)
- ;
-
- break;
- }
- }
-}
-
-static int
-test_thread(void *x)
-{
- int i, j;
- unsigned long ticks;
-
- if (m8xxhci_verbose)
- printk("m8xxhci: test thread starting\n");
-
- lock_kernel();
- exit_files(current);
- daemonize();
- unlock_kernel();
- strcpy(current->comm, "test");
-
- ticks = m8xxhci_timer_ticks;
- while (ticks == m8xxhci_timer_ticks)
- ;
-
- for(;;) {
- for (i = 1300; i > 50; i -= 10) {
- for (j = 0; j < 100; j++)
- send_marker(i);
- }
- }
-
-
- return 0;
-}
-#endif
-
-
/* alloc cpm memory on a 32 byte boundary */
static int
cpm_32b_dpalloc(int size)
@@ -3889,6 +3542,7 @@
static int submit_urb(urb_t *urb, int qtype)
{
struct m8xxhci_device *dev = usb_to_m8xxhci(urb->dev);
+ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
int devnum, endpoint;
unsigned long flags;
struct m8xxhci_qe *qe;
@@ -3900,6 +3554,10 @@
devnum = usb_pipedevice(urb->pipe);
endpoint = usb_pipeendpoint(urb->pipe);
+ /* a request to the virtual root hub */
+ if (usb_pipedevice (urb->pipe) == hp->rh.devnum)
+ return rh_submit_urb (urb);
+
/* build queue element */
qe = allocate_qe(dev, qtype);
if (qe == 0) {
@@ -3992,6 +3650,7 @@
static int
unlink_urb(urb_t *urb, int qtype)
{
+ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
struct m8xxhci_qe *qe;
#if 0
@@ -4006,6 +3665,11 @@
printk("unlink_urb(urb=%p,qtype=%d) status %d\n",
urb, qtype, urb->status);
+ /* a request to the virtual root hub */
+ if (usb_pipedevice (urb->pipe) == hp->rh.devnum) {
+ return rh_unlink_urb (urb);
+ }
+
/* if we're connected to a qe, unlink it */
if ((qe = (struct m8xxhci_qe *)urb->hcpriv)) {
@@ -4054,30 +3718,24 @@
}
static void
-assert_reset(int disable)
+assert_reset()
{
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
volatile immap_t *immap = (immap_t *)IMAP_ADDR;
volatile usbregs_t *usbregs = (usbregs_t *)&immap->im_cpm.cp_scc[0];
-
+
lock_tx_ring(hp);
-disable = 0;
- if (disable) {
- usbregs->usb_usmod &= ~USMOD_EN;
- }
-
/* assert reset */
immap->im_ioport.iop_pcdir |= (PC_USB_TXP | PC_USB_TXN);
immap->im_ioport.iop_pcpar &= ~(PC_USB_TXP | PC_USB_TXN);
immap->im_ioport.iop_pcdat &= ~(PC_USB_TXP | PC_USB_TXN);
- immap->im_ioport.iop_pcdat = 0;
immap->im_ioport.iop_padir |= PA_USB_OE;
immap->im_ioport.iop_papar &= ~PA_USB_OE;
immap->im_ioport.iop_padat &= ~PA_USB_OE;
- udelay(200); /* 200us */
+ wait_ms(20); /* 20ms */
immap->im_ioport.iop_pcdir |= (PC_USB_TXP | PC_USB_TXN);
immap->im_ioport.iop_pcpar |= (PC_USB_TXP | PC_USB_TXN);
@@ -4085,12 +3743,6 @@
immap->im_ioport.iop_padir &= ~PA_USB_OE;
immap->im_ioport.iop_papar |= PA_USB_OE;
- if (disable) {
- usbregs->usb_usmod |= USMOD_EN;
- }
-
- udelay(100); /* 100us */
-
unlock_tx_ring(hp);
}
@@ -4264,7 +3916,7 @@
immap->im_ioport.iop_papar |= (PA_USB_RXD | PA_USB_OE);
immap->im_ioport.iop_paodr &= ~PA_USB_OE;
// immap->im_ioport.iop_padat = 0;
-immap->im_ioport.iop_padat = PA_USB_OE;
+// immap->im_ioport.iop_padat = PA_USB_OE;
/* select USBRXP & USBRXN */
immap->im_ioport.iop_pcdir &= ~(PC_USB_RXP | PC_USB_RXN);
@@ -4291,7 +3943,7 @@
#else
immap->im_ioport.iop_pcdir |= (PC_USB_TXP | PC_USB_TXN);
immap->im_ioport.iop_pcpar |= (PC_USB_TXP | PC_USB_TXN);
- immap->im_ioport.iop_pcdat = 0;
+// immap->im_ioport.iop_pcdat = 0;
#endif
return 0;
@@ -4543,7 +4195,7 @@
/* wait for powerup */
wait_ms(200);
- assert_reset(0);
+// assert_reset();
#if 0
verify_patch(immap);
@@ -4572,6 +4224,8 @@
check_bus();
#endif
+ rh_connect_rh();
+
return 0;
}
@@ -4616,11 +4270,6 @@
if (m8xxhci_verbose)
printk("m8xxhci_alloc_dev(usb_dev=%p)\n", usb_dev);
-#if 0
- printk("dev->bus %p, dev->parent (hub) %p\n", dev->bus, dev->parent);
- dump_root_hub();
-#endif
-
dev = add_local_dev(usb_dev);
if (!dev) {
err("m8xxhci: couldn't allocate internal device");
@@ -4835,19 +4484,6 @@
m8xxhci_events = EV_IDLE;
#endif
- pid = kernel_thread(m8xxhci_thread, NULL,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- if (pid < 0) {
- MOD_DEC_USE_COUNT;
- return pid;
- }
-
-#if TEST_THREAD /* hack */
- pid = kernel_thread(test_thread, NULL,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
-#endif
-
printk("m8xxhci: initializing done\n");
return 0;
@@ -4855,7 +4491,12 @@
static void __exit m8xxhci_cleanup(void)
{
- m8xxhci_disconnect_device();
+ struct m8xxhci_private * hci = (struct m8xxhci_private *) m8xxhci_ptr;
+ if (hci->bus->root_hub)
+ usb_disconnect(&hci->bus->root_hub);
+
+ usb_deregister_bus (hci->bus);
+ usb_free_bus (hci->bus);
}
module_init(m8xxhci_init);
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*
* Virtual Root Hub
* Roman Weissgaerber [EMAIL PROTECTED]
*
*-------------------------------------------------------------------------*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*-------------------------------------------------------------------------*/
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
/* destination of request */
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
#define RH_CLASS 0x20
#define RH_VENDOR 0x40
/* Requests: bRequest << 8 | bmRequestType */
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
#define RH_SET_ADDRESS 0x0500
#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
#define RH_GET_STATE 0x0280
#define RH_GET_INTERFACE 0x0A80
#define RH_SET_INTERFACE 0x0B00
#define RH_SYNC_FRAME 0x0C80
/* Our Vendor Specific Request */
#define RH_SET_EP 0x2000
/* Hub port features */
#define RH_PORT_CONNECTION 0x00
#define RH_PORT_ENABLE 0x01
#define RH_PORT_SUSPEND 0x02
#define RH_PORT_OVER_CURRENT 0x03
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
#define RH_C_PORT_OVER_CURRENT 0x13
#define RH_C_PORT_RESET 0x14
/* Hub features */
#define RH_C_HUB_LOCAL_POWER 0x00
#define RH_C_HUB_OVER_CURRENT 0x01
#define RH_DEVICE_REMOTE_WAKEUP 0x00
#define RH_ENDPOINT_STALL 0x01
#define min(a,b) (((a)<(b))?(a):(b))
/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x10, /* __u16 bcdUSB; v1.1 */
0x01,
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; */
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
0x00, /* __u16 idVendor; */
0x00,
0x00, /* __u16 idProduct; */
0x00,
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* Configuration descriptor */
static __u8 root_hub_config_des[] =
{
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, /* __u16 wTotalLength; */
0x00,
0x01, /* __u8 bNumInterfaces; */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
0x00, /* __u8 MaxPower; */
/* interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* endpoint */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x01, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
0x00,
0xff /* __u8 ep_bInterval; 255 ms */
};
/* Hub class-specific descriptor */
static __u8 root_hub_hub_des[] =
{
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x01, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */
0x00,
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
};
static int get_bus_state (void)
{
volatile immap_t *immap = (immap_t *)IMAP_ADDR;
int ret = 0;
ret = ((immap->im_ioport.iop_pcdat & PC_USB_RXP)? 2 : 0) |
((immap->im_ioport.iop_pcdat & PC_USB_RXN)? 1: 0);
return ret;
}
/*-------------------------------------------------------------------------*/
static int rh_init_int_timer (urb_t * urb);
static __u16 rh_port_status = 0;
static __u16 rh_port_c_status = 0;
/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */
static int rh_send_irq (struct m8xxhci_private * hc, void * rh_data, int rh_len)
{
/* get ptr to 8xx internal registers */
immap_t * immap = (immap_t *)IMAP_ADDR;
/* usb control registers */
usbregs_t * usbregs = (usbregs_t *)&immap->im_cpm.cp_scc[0];
int num_ports;
int ret;
int len;
int bs = 0;
__u8 data[8];
num_ports = 1;
*(__u8 *) data = 0;
ret = *(__u8 *) data;
if (bus_res == 1) {
if (rh_port_status & USB_PORT_STAT_CONNECTION) {
rh_port_c_status |= USB_PORT_STAT_C_CONNECTION;
rh_port_status &= ~USB_PORT_STAT_ENABLE;
usbregs->usb_usmod &= ~USMOD_EN;
}
rh_port_status &= ~(USB_PORT_STAT_CONNECTION);
bus_res = 0;
}
if (!(rh_port_status & USB_PORT_STAT_CONNECTION))
bs = get_bus_state();
if (bs > 0) {
rh_port_status |= USB_PORT_STAT_CONNECTION;
rh_port_c_status |= USB_PORT_STAT_C_CONNECTION;
if (bs == 1) {
rh_port_status |= USB_PORT_STAT_LOW_SPEED;
} else {
rh_port_status &= ~USB_PORT_STAT_LOW_SPEED;
}
}
*(__u8 *) (data + 1) = (rh_port_c_status) ? 2 : 0;
ret += *(__u8 *) (data + 1);
len = 2;
if (ret > 0) {
memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));
printk("\nrh::int:%x %x %x %x %x\n",data[0], data[1], bs,
rh_port_status, rh_port_c_status);
return len;
}
return 0;
}
/*-------------------------------------------------------------------------*/
/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
static void rh_int_timer_do (unsigned long ptr)
{
int len;
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
urb_t * urb = (urb_t *) ptr;
if(hp->rh.send) {
len = rh_send_irq (hp, urb->transfer_buffer,
urb->transfer_buffer_length);
if (len > 0) {
urb->actual_length = len;
if (urb->complete)
urb->complete (urb);
}
}
rh_init_int_timer (urb);
}
/*-------------------------------------------------------------------------*/
/* Root Hub INTs are polled by this timer */
static int rh_init_int_timer (urb_t * urb)
{
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
hp->rh.interval = urb->interval;
init_timer (&hp->rh.rh_int_timer);
hp->rh.rh_int_timer.function = rh_int_timer_do;
hp->rh.rh_int_timer.data = (unsigned long) urb;
hp->rh.rh_int_timer.expires =
jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) /
1000;
add_timer (&hp->rh.rh_int_timer);
return 0;
}
/*-------------------------------------------------------------------------*/
#define OK(x) len = (x); break;
/* request to virtual root hub */
static int rh_submit_urb (urb_t * urb)
{
// struct usb_device * usb_dev = urb->dev;
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
/* get ptr to 8xx internal registers */
immap_t * immap = (immap_t *)IMAP_ADDR;
/* usb control registers */
usbregs_t * usbregs = (usbregs_t *)&immap->im_cpm.cp_scc[0];
unsigned int pipe = urb->pipe;
devrequest * cmd = (devrequest *) urb->setup_packet;
void * data = urb->transfer_buffer;
int leni = urb->transfer_buffer_length;
int len = 0;
int status = 0;
__u32 datab[4];
__u8 * data_buf = (__u8 *) datab;
__u16 bmRType_bReq;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
if (usb_pipeint(pipe)) {
hp->rh.urb = urb;
hp->rh.send = 1;
hp->rh.interval = urb->interval;
rh_init_int_timer(urb);
urb->status = 0;
return 0;
}
bmRType_bReq = cmd->requesttype | (cmd->request << 8);
wValue = le16_to_cpu (cmd->value);
wIndex = le16_to_cpu (cmd->index);
wLength = le16_to_cpu (cmd->length);
dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
bmRType_bReq, wLength);
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
RH_INTERFACE: interface,
RH_ENDPOINT: endpoint,
RH_CLASS means HUB here,
RH_OTHER | RH_CLASS almost ever means HUB_PORT here
*/
case RH_GET_STATUS:
*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
case RH_GET_STATUS | RH_INTERFACE:
*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
case RH_GET_STATUS | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32 (0); OK (4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32 (rh_port_status|
(rh_port_c_status << 16)); OK (4);
case RH_CLEAR_FEATURE | RH_ENDPOINT:
switch (wValue) {
case (RH_ENDPOINT_STALL): OK (0);
}
break;
case RH_CLEAR_FEATURE | RH_CLASS:
switch (wValue) {
case RH_C_HUB_LOCAL_POWER:
OK(0);
case (RH_C_HUB_OVER_CURRENT):
OK (0);
}
break;
case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
case (RH_PORT_ENABLE):
usbregs->usb_usmod &= ~USMOD_EN;
rh_port_status &=
~USB_PORT_STAT_ENABLE;
OK (0);
case (RH_PORT_SUSPEND):
rh_port_status &=
~USB_PORT_STAT_SUSPEND;
OK (0);
case (RH_PORT_POWER):
rh_port_status &= ~USB_PORT_STAT_POWER;
OK (0);
case (RH_C_PORT_CONNECTION):
rh_port_c_status &=
~USB_PORT_STAT_C_CONNECTION;
OK (0);
case (RH_C_PORT_ENABLE):
rh_port_c_status &=
~USB_PORT_STAT_C_ENABLE;
OK (0);
case (RH_C_PORT_SUSPEND):
rh_port_c_status &=
~USB_PORT_STAT_C_SUSPEND;
OK (0);
case (RH_C_PORT_OVER_CURRENT):
rh_port_c_status &=
~USB_PORT_STAT_C_OVERCURRENT;
OK (0);
case (RH_C_PORT_RESET):
rh_port_c_status &=
~USB_PORT_STAT_C_RESET;
OK (0);
}
break;
case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
switch (wValue) {
case (RH_PORT_SUSPEND):
// assert_suspend(1);
OK (0);
case (RH_PORT_RESET):
bus_res = 0;
usbregs->usb_usmod |= USMOD_EN;
wait_ms(20);
usbregs->usb_usmod &= ~USMOD_EN;
assert_reset();
usbregs->usb_usmod |= USMOD_EN;
rh_port_status |= USB_PORT_STAT_ENABLE;
wait_ms(200);
OK (0);
case (RH_PORT_POWER):
// mdelay(200);
rh_port_status |= USB_PORT_STAT_POWER;
OK (0);
case (RH_PORT_ENABLE):
usbregs->usb_usmod |= USMOD_EN;
rh_port_status |= USB_PORT_STAT_ENABLE;
OK (0);
}
break;
case RH_SET_ADDRESS: hp->rh.devnum = wValue; OK(0);
case RH_GET_DESCRIPTOR:
switch ((wValue & 0xff00) >> 8) {
case (0x01): /* device descriptor */
len = min (leni, min (sizeof
(root_hub_dev_des), wLength));
data_buf = root_hub_dev_des; OK(len);
case (0x02): /* configuration descriptor */
len = min (leni, min (sizeof
(root_hub_config_des), wLength));
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff,
(int)(long) hp, "m8xxHCI",
data, wLength);
if (len > 0) {
data_buf = data;
OK (min (leni, len));
}
// else fallthrough
default:
status = -EPIPE;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
len = min (leni, min (sizeof (root_hub_hub_des),
wLength));
data_buf = root_hub_hub_des; OK(len);
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
case RH_SET_CONFIGURATION: OK (0);
default:
dbg ("unsupported root hub command");
status = -EPIPE;
}
len = min(len, leni);
if (data != data_buf)
memcpy (data, data_buf, len);
urb->actual_length = len;
urb->status = status;
urb->hcpriv = NULL;
// usb_dec_dev_use (usb_dev);
urb->dev = NULL;
if (urb->complete)
urb->complete (urb);
return 0;
}
/*-------------------------------------------------------------------------*/
static int rh_unlink_urb (urb_t * urb)
{
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
if (hp->rh.urb == urb) {
hp->rh.send = 0;
del_timer (&hp->rh.rh_int_timer);
hp->rh.urb = NULL;
urb->hcpriv = NULL;
// usb_dec_dev_use(urb->dev);
urb->dev = NULL;
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete (urb);
} else
urb->status = -ENOENT;
}
return 0;
}
/*-------------------------------------------------------------------------*/
/* connect the virtual root hub */
static int rh_connect_rh (void) {
struct m8xxhci_private * hci = (struct m8xxhci_private *) m8xxhci_ptr;
struct usb_device * usb_dev;
struct m8xxhci_device * dev;
hci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, hci->bus);
if (!usb_dev)
return -ENOMEM;
dev = usb_to_m8xxhci (usb_dev);
hci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
return -ENODEV;
}
return 0;
}