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 = &dd;
-       }
-
-       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;
}

Reply via email to