X-Git-Url: https://git.stricted.de/?p=GitHub%2Fmt8127%2Fandroid_kernel_alcatel_ttab.git;a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fxhci.c;h=10a9804a08c2962ca8c78e660f1efe7083701f16;hp=d8f640b12dd9d950e842892858a617b7fa97247e;hb=dd388bd4cd025a2198aa760395d6aefe4eca74f3;hpb=78750f1908869c3bfcbf2a1f1f00f078f2948271 diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d8f640b12dd9..10a9804a08c2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -30,6 +30,29 @@ #include "xhci.h" +#ifdef CONFIG_MTK_XHCI +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USBIF_COMPLIANCE +#include +#include +#include +#include +#include + +static struct miscdevice mu3h_uevent_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "usbif_u3h_uevent", + .fops = NULL, +}; +#endif +#endif + #define DRIVER_AUTHOR "Sarah Sharp" #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" @@ -38,6 +61,23 @@ static int link_quirk; module_param(link_quirk, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); +#ifdef CONFIG_USBIF_COMPLIANCE +int usbif_u3h_send_event(char* event) +{ + char udev_event[128]; + char *envp[] = {udev_event, NULL }; + int ret ; + + snprintf(udev_event, 128, "USBIF_EVENT=%s",event); + printk("usbif_u3h_send_event - sending event - %s in %s\n", udev_event, kobject_get_path(&mu3h_uevent_device.this_device->kobj, GFP_KERNEL)); + ret = kobject_uevent_env(&mu3h_uevent_device.this_device->kobj, KOBJ_CHANGE, envp); + if (ret < 0) + printk("usbif_u3h_send_event sending failed with ret = %d, \n", ret); + + return ret; +} +#endif + /* TODO: copied from ehci-hcd.c - can this be refactored? */ /* * xhci_handshake - spin reading hc until handshake completes or fails @@ -139,7 +179,8 @@ static int xhci_start(struct xhci_hcd *xhci) "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); if (!ret) - xhci->xhc_state &= ~XHCI_STATE_HALTED; + xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING); + return ret; } @@ -315,6 +356,9 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + if (xhci->quirks & XHCI_PLAT) + return; + xhci_free_irq(xhci); if (xhci->msix_entries) { @@ -342,9 +386,14 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) static int xhci_try_enable_msi(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct pci_dev *pdev; int ret; + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); /* * Some Fresco Logic host controllers advertise MSI, but fail to * generate interrupts. Don't even try to enable MSI. @@ -386,16 +435,16 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) #else -static int xhci_try_enable_msi(struct usb_hcd *hcd) +static inline int xhci_try_enable_msi(struct usb_hcd *hcd) { return 0; } -static void xhci_cleanup_msix(struct xhci_hcd *xhci) +static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) { } -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) { } @@ -513,6 +562,7 @@ int xhci_init(struct usb_hcd *hcd) } else { xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n"); } + retval = xhci_mem_init(xhci, GFP_KERNEL); xhci_dbg(xhci, "Finished xhci_init\n"); @@ -585,6 +635,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci) xhci_halt(xhci); return -ENODEV; } + xhci->shared_hcd->state = HC_STATE_RUNNING; xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; @@ -592,6 +643,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci) xhci_ring_cmd_db(xhci); xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n"); + return 0; } @@ -738,10 +790,10 @@ void xhci_stop(struct usb_hcd *hcd) xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n", __func__); } - +#ifndef CONFIG_MTK_XHCI if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_dev_put(); - +#endif xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); @@ -952,7 +1004,7 @@ int xhci_suspend(struct xhci_hcd *xhci) */ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { - u32 command, temp = 0; + u32 command, temp = 0, status; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; @@ -1076,8 +1128,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) done: if (retval == 0) { - usb_hcd_resume_root_hub(hcd); - usb_hcd_resume_root_hub(xhci->shared_hcd); + /* Resume root hubs only when have pending events. */ + status = readl(&xhci->op_regs->status); + if (status & STS_EINT) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } } /* @@ -1171,9 +1227,6 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, } xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_HALTED) - return -ENODEV; - if (check_virt_dev) { if (!udev->slot_id || !xhci->devs[udev->slot_id]) { printk(KERN_DEBUG "xHCI %s called with unaddressed " @@ -1189,6 +1242,9 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, } } + if (xhci->xhc_state & XHCI_STATE_HALTED) + return -ENODEV; + return 1; } @@ -1287,6 +1343,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; + else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && + urb->transfer_buffer_length > 0 && + urb->transfer_flags & URB_ZERO_PACKET && + !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) + size = 2; else size = 1; @@ -1578,6 +1639,11 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, u32 drop_flag; u32 new_add_flags, new_drop_flags, new_slot_info; int ret; +#ifdef CONFIG_MTK_XHCI + struct sch_ep *sch_ep = NULL; + int isTT; + int ep_type = 0; +#endif ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); if (ret <= 0) @@ -1629,12 +1695,44 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); +#ifdef CONFIG_MTK_XHCI + slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[udev->slot_id]->out_ctx); + if((slot_ctx->tt_info & 0xff) > 0){ + isTT = 1; + } + else{ + isTT = 0; + } + if(usb_endpoint_xfer_int(&ep->desc)){ + ep_type = USB_EP_INT; + } + else if(usb_endpoint_xfer_isoc(&ep->desc)){ + ep_type = USB_EP_ISOC; + } + else if(usb_endpoint_xfer_bulk(&ep->desc)){ + ep_type = USB_EP_BULK; + } + sch_ep = mtk_xhci_scheduler_remove_ep(udev->speed, usb_endpoint_dir_in(&ep->desc) + , isTT, ep_type, (mtk_u32 *)ep); + if(sch_ep != NULL){ + kfree(sch_ep); + } + else{ + xhci_warn(xhci, "[MTK]Doesn't find ep_sch instance when removing endpoint\n"); + } +#endif + xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, (unsigned int) new_drop_flags, (unsigned int) new_add_flags, (unsigned int) new_slot_info); + + #if defined(CONFIG_MTK_XHCI) && defined(CONFIG_USB_MTK_DUALMODE) + mtk_ep_count_dec(); + #endif + return 0; } @@ -1664,6 +1762,16 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, u32 new_add_flags, new_drop_flags, new_slot_info; struct xhci_virt_device *virt_dev; int ret = 0; +#ifdef CONFIG_MTK_XHCI + struct xhci_ep_ctx *in_ep_ctx; + struct sch_ep *sch_ep; + int isTT; + int ep_type = 0; + int maxp = 0; + int burst = 0; + int mult = 0; + int interval = 0; +#endif ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); if (ret <= 0) { @@ -1726,6 +1834,46 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return -ENOMEM; } +#ifdef CONFIG_MTK_XHCI + in_ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); + + if((slot_ctx->tt_info & 0xff) > 0){ + isTT = 1; + } + else{ + isTT = 0; + } + if(usb_endpoint_xfer_int(&ep->desc)){ + ep_type = USB_EP_INT; + } + else if(usb_endpoint_xfer_isoc(&ep->desc)){ + ep_type = USB_EP_ISOC; + } + else if(usb_endpoint_xfer_bulk(&ep->desc)){ + ep_type = USB_EP_BULK; + } + if(udev->speed == USB_SPEED_FULL || udev->speed == USB_SPEED_HIGH + || udev->speed == USB_SPEED_LOW){ + maxp = ep->desc.wMaxPacketSize & 0x7FF; + burst = ep->desc.wMaxPacketSize >> 11; + mult = 0; + } + else if(udev->speed == USB_SPEED_SUPER){ + maxp = ep->desc.wMaxPacketSize & 0x7FF; + burst = ep->ss_ep_comp.bMaxBurst; + mult = ep->ss_ep_comp.bmAttributes & 0x3; + } + interval = (1 << ((in_ep_ctx->ep_info >> 16) & 0xff)); + sch_ep = kmalloc(sizeof(struct sch_ep), GFP_KERNEL); + if(mtk_xhci_scheduler_add_ep(udev->speed, usb_endpoint_dir_in(&ep->desc), + isTT, ep_type, maxp, interval, burst, mult, (mtk_u32 *)ep + , (mtk_u32 *)in_ep_ctx, sch_ep) != SCH_SUCCESS){ + xhci_err(xhci, "[MTK] not enough bandwidth\n"); + return -ENOSPC; + } +#endif + ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs); new_add_flags = le32_to_cpu(ctrl_ctx->add_flags); @@ -1755,6 +1903,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, (unsigned int) new_drop_flags, (unsigned int) new_add_flags, (unsigned int) new_slot_info); + + #if defined(CONFIG_MTK_XHCI) && defined(CONFIG_USB_MTK_DUALMODE) + mtk_ep_count_inc(); + #endif + return 0; } @@ -2587,15 +2740,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, if (command) { cmd_completion = command->completion; cmd_status = &command->status; - command->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) - command->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - + command->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); list_add_tail(&command->cmd_list, &virt_dev->cmd_list); } else { cmd_completion = &virt_dev->cmd_completion; @@ -2603,7 +2748,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, } init_completion(cmd_completion); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); if (!ctx_change) ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, udev->slot_id, must_succeed); @@ -3352,6 +3497,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) return -EINVAL; } + if (virt_dev->tt_info) + old_active_eps = virt_dev->tt_info->active_eps; + if (virt_dev->udev != udev) { /* If the virt_dev and the udev does not match, this virt_dev * may belong to another udev. @@ -3388,14 +3536,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); - reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) - reset_device_cmd->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; + reset_device_cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); ret = xhci_queue_reset_device(xhci, slot_id); @@ -3506,10 +3647,23 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_virt_device *virt_dev; +#ifndef CONFIG_USB_DEFAULT_PERSIST + struct device *dev = hcd->self.controller; +#endif unsigned long flags; u32 state; int i, ret; +#ifndef CONFIG_USB_DEFAULT_PERSIST + /* + * We called pm_runtime_get_noresume when the device was attached. + * Decrement the counter here to allow controller to runtime suspend + * if no devices remain. + */ + if (xhci->quirks & XHCI_RESET_ON_RESUME) + pm_runtime_put_noidle(dev); +#endif + ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); /* If the host is halted due to driver unload, we still need to free the * device. @@ -3581,13 +3735,14 @@ static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci) int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct device *dev = hcd->self.controller; unsigned long flags; int timeleft; int ret; union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -3633,6 +3788,16 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) goto disable_slot; } udev->slot_id = xhci->slot_id; + +#ifndef CONFIG_USB_DEFAULT_PERSIST + /* + * If resetting upon resume, we can't put the controller into runtime + * suspend if there is a device attached. + */ + if (xhci->quirks & XHCI_RESET_ON_RESUME) + pm_runtime_get_noresume(dev); +#endif + /* Is this a LS or FS device under a HS hub? */ /* Hub or peripherial? */ return 1; @@ -3704,7 +3869,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret) { @@ -4388,13 +4553,21 @@ static int xhci_change_max_exit_latency(struct xhci_hcd *xhci, int ret; spin_lock_irqsave(&xhci->lock, flags); - if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + + virt_dev = xhci->devs[udev->slot_id]; + + /* + * virt_dev might not exists yet if xHC resumed from hibernate (S4) and + * xHC was re-initialized. Exit latency will be set later after + * hub_port_finish_reset() is done and xhci->devs[] are re-allocated + */ + + if (!virt_dev || max_exit_latency == virt_dev->current_mel) { spin_unlock_irqrestore(&xhci->lock, flags); return 0; } /* Attempt to issue an Evaluate Context command to change the MEL. */ - virt_dev = xhci->devs[udev->slot_id]; command = xhci->lpm_command; xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); spin_unlock_irqrestore(&xhci->lock, flags); @@ -4579,8 +4752,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); + /* + * refer to section 6.2.2: MTT should be 0 for full speed hub, + * but it may be already set to 1 when setup an xHCI virtual + * device, so clear it anyway. + */ if (tt->multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); + else if (hdev->speed == USB_SPEED_FULL) + slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT); + if (xhci->hci_version > 0x95) { xhci_dbg(xhci, "xHCI version %x needs hub " "TT think time and number of ports\n", @@ -4681,6 +4862,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) return 0; } +#ifdef CONFIG_MTK_XHCI + retval = mtk_xhci_ip_init(hcd, xhci); + if(retval) + goto error; +#endif + xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); @@ -4697,6 +4884,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) get_quirks(dev, xhci); + /* In xhci controllers which follow xhci 1.0 spec gives a spurious + * success event after a short transfer. This quirk will ignore such + * spurious event. + */ + if (xhci->hci_version > 0x96) + xhci->quirks |= XHCI_SPURIOUS_SUCCESS; + /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) @@ -4723,6 +4917,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) if (retval) goto error; xhci_dbg(xhci, "Called HCD init\n"); + + printk("%s(%d): do mtk_xhci_set\n", __func__, __LINE__); + return 0; error: kfree(xhci); @@ -4733,10 +4930,196 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); +#ifdef CONFIG_USBIF_COMPLIANCE +#ifndef CONFIG_USB_MTK_DUALMODE +static int xhci_hcd_driver_init(void) +{ + int retval; + + retval = xhci_register_pci(); + if (retval < 0) { + printk(KERN_DEBUG "Problem registering PCI driver."); + return retval; + } + + #ifdef CONFIG_MTK_XHCI + mtk_xhci_ip_init(); + #endif + + retval = xhci_register_plat(); + if (retval < 0) { + printk(KERN_DEBUG "Problem registering platform driver."); + goto unreg_pci; + } + + #ifdef CONFIG_MTK_XHCI + retval = xhci_attrs_init(); + if(retval < 0){ + printk(KERN_DEBUG "Problem creating xhci attributes."); + goto unreg_plat; + } + + mtk_xhci_wakelock_init(); + #endif + + /* + * Check the compiler generated sizes of structures that must be laid + * out in specific ways for hardware access. + */ + BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); + BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8); + BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8); + /* xhci_device_control has eight fields, and also + * embeds one xhci_slot_ctx and 31 xhci_ep_ctx + */ + BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8); + BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8); + BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); + BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8); + BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); + /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ + BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + return 0; + +#ifdef CONFIG_MTK_XHCI +unreg_plat: + xhci_unregister_plat(); +#endif +unreg_pci: + xhci_unregister_pci(); + return retval; +} + +static void xhci_hcd_driver_cleanup(void) +{ + xhci_unregister_pci(); + xhci_unregister_plat(); + xhci_attrs_exit(); +} +#else +static int xhci_hcd_driver_init(void) +{ + // init in mt_devs.c + mtk_xhci_eint_iddig_init(); + mtk_xhci_switch_init(); + //mtk_xhci_wakelock_init(); + return 0; +} + +static void xhci_hcd_driver_cleanup(void) +{ + mtk_xhci_eint_iddig_deinit() ; +} + +#endif + +static int mu3h_normal_driver_on = 0 ; + +static int xhci_mu3h_proc_show(struct seq_file *seq, void *v) +{ + seq_printf(seq, "xhci_mu3h_proc_show, mu3h is %d (on:1, off:0)\n", mu3h_normal_driver_on); + return 0; +} + +static int xhci_mu3h_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, xhci_mu3h_proc_show, inode->i_private); +} + +static ssize_t xhci_mu3h_proc_write(struct file *file, const char __user *buf, size_t length, loff_t *ppos) +{ + int ret ; + char msg[32] ; + int result; + + if (length >= sizeof(msg)) { + printk( "xhci_mu3h_proc_write length error, the error len is %d\n", (unsigned int)length); + return -EINVAL; + } + if (copy_from_user(msg, buf, length)) + return -EFAULT; + + msg[length] = 0 ; + + printk("xhci_mu3h_proc_write: %s, current driver on/off: %d\n", msg, mu3h_normal_driver_on); + + if ((msg[0] == '1') && (mu3h_normal_driver_on == 0)){ + xhci_hcd_driver_init() ; + mu3h_normal_driver_on = 1 ; + printk("registe mu3h driver : m3h xhci driver\n"); + }else if ((msg[0] == '0') && (mu3h_normal_driver_on == 1)){ + xhci_hcd_driver_cleanup(); + mu3h_normal_driver_on = 0 ; + printk("unregiste m3h xhci driver.\n"); + }else{ + printk("xhci_mu3h_proc_write write faile !\n"); + } + return length; +} + +static const struct file_operations mu3h_proc_fops = { + .owner = THIS_MODULE, + .open = xhci_mu3h_proc_open, + .write = xhci_mu3h_proc_write, + .read = seq_read, + .llseek = seq_lseek, + +}; + +static int __init xhci_hcd_init(void) +{ + struct proc_dir_entry *prEntry; + + printk(KERN_DEBUG "xhci_hcd_init"); + + // set xhci up at boot up + xhci_hcd_driver_init() ; + mtk_xhci_wakelock_init(); + mu3h_normal_driver_on = 1; + + // USBIF + prEntry = proc_create("mu3h_driver_init", 0666, NULL, &mu3h_proc_fops); + if (prEntry) + { + printk("create the mu3h init proc OK!\n") ; + }else{ + printk("[ERROR] create the mu3h init proc FAIL\n") ; + } + +#ifdef CONFIG_MTK_XHCI + + if (!misc_register(&mu3h_uevent_device)){ + printk("create the mu3h_uevent_device uevent device OK!\n") ; + + }else{ + printk("[ERROR] create the mu3h_uevent_device uevent device fail\n") ; + } + +#endif + + return 0 ; + +} +module_init(xhci_hcd_init); + +static void __exit xhci_hcd_cleanup(void) +{ +#ifdef CONFIG_MTK_XHCI + misc_deregister(&mu3h_uevent_device); +#endif + printk(KERN_DEBUG "xhci_hcd_cleanup"); +} +module_exit(xhci_hcd_cleanup); + +#else +#ifndef CONFIG_USB_MTK_DUALMODE static int __init xhci_hcd_init(void) { int retval; + if (usb_disabled()) + return -ENODEV; + retval = xhci_register_pci(); if (retval < 0) { printk(KERN_DEBUG "Problem registering PCI driver."); @@ -4747,6 +5130,17 @@ static int __init xhci_hcd_init(void) printk(KERN_DEBUG "Problem registering platform driver."); goto unreg_pci; } + + #ifdef CONFIG_MTK_XHCI + retval = xhci_attrs_init(); + if(retval < 0){ + printk(KERN_DEBUG "Problem creating xhci attributes."); + goto unreg_plat; + } + + mtk_xhci_wakelock_init(); + #endif + /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -4764,7 +5158,13 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + return 0; + +#ifdef CONFIG_MTK_XHCI +unreg_plat: + xhci_unregister_plat(); +#endif unreg_pci: xhci_unregister_pci(); return retval; @@ -4775,5 +5175,23 @@ static void __exit xhci_hcd_cleanup(void) { xhci_unregister_pci(); xhci_unregister_plat(); + xhci_attrs_exit(); } module_exit(xhci_hcd_cleanup); +#else +static int __init xhci_hcd_init(void) +{ + mtk_xhci_eint_iddig_init(); + mtk_xhci_switch_init(); + mtk_xhci_wakelock_init(); + return 0; +} +module_init(xhci_hcd_init); + +static void __exit xhci_hcd_cleanup(void) +{ +} +module_exit(xhci_hcd_cleanup); + +#endif +#endif