提交 1be1d6b7 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (32 commits)
  USB GADGET/PERIPHERAL: g_file_storage Bulk-Only Transport compliance, clear-feature ignore
  USB GADGET/PERIPHERAL: g_file_storage Bulk-Only Transport compliance
  usb_serial: some coding style fixes
  USB: Remove redundant dependencies on USB_ATM.
  USB: UHCI: disable remote wakeup when it's not needed
  USB: OHCI: work around bogus compiler warning
  USB: add Cypress c67x00 OTG controller HCD driver
  USB: add Cypress c67x00 OTG controller core driver
  USB: add Cypress c67x00 low level interface code
  USB: airprime: unlock mutex instead of trying to lock it again
  USB: storage: Update mailling list address
  USB: storage: UNUSUAL_DEVS() for PanDigital Picture frame.
  USB: Add the USB 2.0 extension descriptor.
  USB: add more FTDI device ids
  USB: fix cannot work usb storage when using ohci-sm501
  usb: gadget zero timer init fix
  usb: gadget zero style fixups (mostly whitespace)
  usb serial gadget: CDC ACM fixes
  usb: pxa27x_udc driver
  USB: INTOVA Pixtreme camera mass storage device
  ...
......@@ -4051,6 +4051,12 @@ L: linux-usb@vger.kernel.org
S: Maintained
W: http://www.kroah.com/linux-usb/
USB CYPRESS C67X00 DRIVER
P: Peter Korsgaard
M: jacmet@sunsite.dk
L: linux-usb@vger.kernel.org
S: Maintained
USB DAVICOM DM9601 DRIVER
P: Peter Korsgaard
M: jacmet@sunsite.dk
......
......@@ -205,6 +205,7 @@ struct ub_scsi_cmd {
unsigned char key, asc, ascq; /* May be valid if error==-EIO */
int stat_count; /* Retries getting status. */
unsigned int timeo; /* jiffies until rq->timeout changes */
unsigned int len; /* Requested length */
unsigned int current_sg;
......@@ -318,6 +319,7 @@ struct ub_dev {
int openc; /* protected by ub_lock! */
/* kref is too implicit for our taste */
int reset; /* Reset is running */
int bad_resid;
unsigned int tagcnt;
char name[12];
struct usb_device *dev;
......@@ -764,6 +766,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
/*
* To reapply this to every URB is not as incorrect as it looks.
* In return, we avoid any complicated tracking calculations.
*/
cmd->timeo = rq->timeout;
}
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
......@@ -785,10 +793,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scsi_status = 0;
} else {
if (cmd->act_len != cmd->len) {
if ((cmd->key == MEDIUM_ERROR ||
cmd->key == UNIT_ATTENTION) &&
ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
scsi_status = SAM_STAT_CHECK_CONDITION;
} else {
scsi_status = 0;
......@@ -804,7 +808,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
else
scsi_status = DID_ERROR << 16;
} else {
if (cmd->error == -EIO) {
if (cmd->error == -EIO &&
(cmd->key == 0 ||
cmd->key == MEDIUM_ERROR ||
cmd->key == UNIT_ATTENTION)) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
......@@ -1259,14 +1266,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
len = le32_to_cpu(bcs->Residue);
if (len != cmd->len - cmd->act_len) {
/*
* It is all right to transfer less, the caller has
* to check. But it's not all right if the device
* counts disagree with our counts.
*/
goto Bad_End;
if (!sc->bad_resid) {
len = le32_to_cpu(bcs->Residue);
if (len != cmd->len - cmd->act_len) {
/*
* Only start ignoring if this cmd ended well.
*/
if (cmd->len == cmd->act_len) {
printk(KERN_NOTICE "%s: "
"bad residual %d of %d, ignoring\n",
sc->name, len, cmd->len);
sc->bad_resid = 1;
}
}
}
switch (bcs->Status) {
......@@ -1297,8 +1309,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
ub_state_done(sc, cmd, -EIO);
} else {
printk(KERN_WARNING "%s: "
"wrong command state %d\n",
printk(KERN_WARNING "%s: wrong command state %d\n",
sc->name, cmd->state);
ub_state_done(sc, cmd, -EINVAL);
return;
......@@ -1336,7 +1347,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
if (cmd->timeo)
sc->work_timer.expires = jiffies + cmd->timeo;
else
sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
......@@ -1376,7 +1390,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return -1;
}
sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
if (cmd->timeo)
sc->work_timer.expires = jiffies + cmd->timeo;
else
sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
add_timer(&sc->work_timer);
return 0;
}
......@@ -1515,8 +1532,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
return;
}
if (cmd->state != UB_CMDST_SENSE) {
printk(KERN_WARNING "%s: "
"sense done with bad cmd state %d\n",
printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
sc->name, cmd->state);
return;
}
......@@ -1720,7 +1736,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
}
/*
* This is called once a new disk was seen by the block layer or by ub_probe().
* This is called by check_disk_change if we reported a media change.
* The main onjective here is to discover the features of the media such as
* the capacity, read-only status, etc. USB storage generally does not
* need to be spun up, but if we needed it, this would be the place.
......@@ -2136,8 +2152,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
}
if (ep_in == NULL || ep_out == NULL) {
printk(KERN_NOTICE "%s: failed endpoint check\n",
sc->name);
printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
return -ENODEV;
}
......@@ -2354,7 +2369,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(&ub_lock, flags);
/*
* Fence stall clearnings, operations triggered by unlinkings and so on.
* Fence stall clearings, operations triggered by unlinkings and so on.
* We do not attempt to unlink any URBs, because we do not trust the
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
*/
......@@ -2417,7 +2432,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(sc->lock, flags);
/*
* There is virtually no chance that other CPU runs times so long
* There is virtually no chance that other CPU runs a timeout so long
* after ub_urb_complete should have called del_timer, but only if HCD
* didn't forget to deliver a callback on unlink.
*/
......
......@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
......
......@@ -19,7 +19,6 @@ if USB_ATM
config USB_SPEEDTOUCH
tristate "Speedtouch USB support"
depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an SpeedTouch USB or SpeedTouch 330
......@@ -32,7 +31,6 @@ config USB_SPEEDTOUCH
config USB_CXACRU
tristate "Conexant AccessRunner USB support"
depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the Conexant
......@@ -45,7 +43,6 @@ config USB_CXACRU
config USB_UEAGLEATM
tristate "ADI 930 and eagle USB DSL modem"
depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the ADI 930
......@@ -58,7 +55,6 @@ config USB_UEAGLEATM
config USB_XUSBATM
tristate "Other USB DSL modem support"
depends on USB_ATM
help
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
......
#
# Makefile for Cypress C67X00 USB Controller
#
ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
/*
* c67x00-drv.c: Cypress C67X00 USB Common infrastructure
*
* Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
/*
* This file implements the common infrastructure for using the c67x00.
* It is both the link between the platform configuration and subdrivers and
* the link between the common hardware parts and the subdrivers (e.g.
* interrupt handling).
*
* The c67x00 has 2 SIE's (serial interface engine) wich can be configured
* to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
*
* Depending on the platform configuration, the SIE's are created and
* the corresponding subdriver is initialized (c67x00_probe_sie).
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/usb/c67x00.h>
#include "c67x00.h"
#include "c67x00-hcd.h"
static void c67x00_probe_sie(struct c67x00_sie *sie,
struct c67x00_device *dev, int sie_num)
{
spin_lock_init(&sie->lock);
sie->dev = dev;
sie->sie_num = sie_num;
sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
switch (sie->mode) {
case C67X00_SIE_HOST:
c67x00_hcd_probe(sie);
break;
case C67X00_SIE_UNUSED:
dev_info(sie_dev(sie),
"Not using SIE %d as requested\n", sie->sie_num);
break;
default:
dev_err(sie_dev(sie),
"Unsupported configuration: 0x%x for SIE %d\n",
sie->mode, sie->sie_num);
break;
}
}
static void c67x00_remove_sie(struct c67x00_sie *sie)
{
switch (sie->mode) {
case C67X00_SIE_HOST:
c67x00_hcd_remove(sie);
break;
default:
break;
}
}
static irqreturn_t c67x00_irq(int irq, void *__dev)
{
struct c67x00_device *c67x00 = __dev;
struct c67x00_sie *sie;
u16 msg, int_status;
int i, count = 8;
int_status = c67x00_ll_hpi_status(c67x00);
if (!int_status)
return IRQ_NONE;
while (int_status != 0 && (count-- >= 0)) {
c67x00_ll_irq(c67x00, int_status);
for (i = 0; i < C67X00_SIES; i++) {
sie = &c67x00->sie[i];
msg = 0;
if (int_status & SIEMSG_FLG(i))
msg = c67x00_ll_fetch_siemsg(c67x00, i);
if (sie->irq)
sie->irq(sie, int_status, msg);
}
int_status = c67x00_ll_hpi_status(c67x00);
}
if (int_status)
dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
"status = 0x%04x\n", int_status);
return IRQ_HANDLED;
}
/* ------------------------------------------------------------------------- */
static int __devinit c67x00_drv_probe(struct platform_device *pdev)
{
struct c67x00_device *c67x00;
struct c67x00_platform_data *pdata;
struct resource *res, *res2;
int ret, i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res2)
return -ENODEV;
pdata = pdev->dev.platform_data;
if (!pdata)
return -ENODEV;
c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
if (!c67x00)
return -ENOMEM;
if (!request_mem_region(res->start, res->end - res->start + 1,
pdev->name)) {
dev_err(&pdev->dev, "Memory region busy\n");
ret = -EBUSY;
goto request_mem_failed;
}
c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
if (!c67x00->hpi.base) {
dev_err(&pdev->dev, "Unable to map HPI registers\n");
ret = -EIO;
goto map_failed;
}
spin_lock_init(&c67x00->hpi.lock);
c67x00->hpi.regstep = pdata->hpi_regstep;
c67x00->pdata = pdev->dev.platform_data;
c67x00->pdev = pdev;
c67x00_ll_init(c67x00);
c67x00_ll_hpi_reg_init(c67x00);
ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
if (ret) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
goto request_irq_failed;
}
ret = c67x00_ll_reset(c67x00);
if (ret) {
dev_err(&pdev->dev, "Device reset failed\n");
goto reset_failed;
}
for (i = 0; i < C67X00_SIES; i++)
c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
platform_set_drvdata(pdev, c67x00);
return 0;
reset_failed:
free_irq(res2->start, c67x00);
request_irq_failed:
iounmap(c67x00->hpi.base);
map_failed:
release_mem_region(res->start, res->end - res->start + 1);
request_mem_failed:
kfree(c67x00);
return ret;
}
static int __devexit c67x00_drv_remove(struct platform_device *pdev)
{
struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
struct resource *res;
int i;
for (i = 0; i < C67X00_SIES; i++)
c67x00_remove_sie(&c67x00->sie[i]);
c67x00_ll_release(c67x00);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res)
free_irq(res->start, c67x00);
iounmap(c67x00->hpi.base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, res->end - res->start + 1);
kfree(c67x00);
return 0;
}
static struct platform_driver c67x00_driver = {
.probe = c67x00_drv_probe,
.remove = __devexit_p(c67x00_drv_remove),
.driver = {
.owner = THIS_MODULE,
.name = "c67x00",
},
};
MODULE_ALIAS("platform:c67x00");
static int __init c67x00_init(void)
{
return platform_driver_register(&c67x00_driver);
}
static void __exit c67x00_exit(void)
{
platform_driver_unregister(&c67x00_driver);
}
module_init(c67x00_init);
module_exit(c67x00_exit);
MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
MODULE_LICENSE("GPL");
/*
* c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
*
* Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include "c67x00.h"
#include "c67x00-hcd.h"
/* --------------------------------------------------------------------------
* Root Hub Support
*/
static __u8 c67x00_hub_des[] = {
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */
0x00, /* (per-port OC, no power switching) */
0x32, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */
0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */
};
static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
{
struct c67x00_hcd *c67x00 = sie->private_data;
unsigned long flags;
c67x00_ll_husb_reset(sie, port);
spin_lock_irqsave(&c67x00->lock, flags);
c67x00_ll_husb_reset_port(sie, port);
spin_unlock_irqrestore(&c67x00->lock, flags);
c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
}
static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
struct c67x00_sie *sie = c67x00->sie;
u16 status;
int i;
*buf = 0;
status = c67x00_ll_usb_get_status(sie);
for (i = 0; i < C67X00_PORTS; i++)
if (status & PORT_CONNECT_CHANGE(i))
*buf |= (1 << i);
/* bit 0 denotes hub change, b1..n port change */
*buf <<= 1;
return !!*buf;
}
static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
struct c67x00_sie *sie = c67x00->sie;
u16 status, usb_status;
int len = 0;
unsigned int port = wIndex-1;
u16 wPortChange, wPortStatus;
switch (typeReq) {
case GetHubStatus:
*(__le32 *) buf = cpu_to_le32(0);
len = 4; /* hub power */
break;
case GetPortStatus:
if (wIndex > C67X00_PORTS)
return -EPIPE;
status = c67x00_ll_usb_get_status(sie);
usb_status = c67x00_ll_get_usb_ctl(sie);
wPortChange = 0;
if (status & PORT_CONNECT_CHANGE(port))
wPortChange |= USB_PORT_STAT_C_CONNECTION;
wPortStatus = USB_PORT_STAT_POWER;
if (!(status & PORT_SE0_STATUS(port)))
wPortStatus |= USB_PORT_STAT_CONNECTION;
if (usb_status & LOW_SPEED_PORT(port)) {
wPortStatus |= USB_PORT_STAT_LOW_SPEED;
c67x00->low_speed_ports |= (1 << port);
} else
c67x00->low_speed_ports &= ~(1 << port);
if (usb_status & SOF_EOP_EN(port))
wPortStatus |= USB_PORT_STAT_ENABLE;
*(__le16 *) buf = cpu_to_le16(wPortStatus);
*(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
len = 4;
break;
case SetHubFeature: /* We don't implement these */
case ClearHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
len = 0;
break;
default:
return -EPIPE;
}
break;
case SetPortFeature:
if (wIndex > C67X00_PORTS)
return -EPIPE;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
dev_dbg(c67x00_hcd_dev(c67x00),
"SetPortFeature %d (SUSPEND)\n", port);
len = 0;
break;
case USB_PORT_FEAT_RESET:
c67x00_hub_reset_host_port(sie, port);
len = 0;
break;
case USB_PORT_FEAT_POWER:
/* Power always enabled */
len = 0;
break;
default:
dev_dbg(c67x00_hcd_dev(c67x00),
"%s: SetPortFeature %d (0x%04x) Error!\n",
__func__, port, wValue);
return -EPIPE;
}
break;
case ClearPortFeature:
if (wIndex > C67X00_PORTS)
return -EPIPE;
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
/* Reset the port so that the c67x00 also notices the
* disconnect */
c67x00_hub_reset_host_port(sie, port);
len = 0;
break;
case USB_PORT_FEAT_C_ENABLE:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): C_ENABLE\n", port);
len = 0;
break;
case USB_PORT_FEAT_SUSPEND:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): SUSPEND\n", port);
len = 0;
break;
case USB_PORT_FEAT_C_SUSPEND:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): C_SUSPEND\n", port);
len = 0;
break;
case USB_PORT_FEAT_POWER:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): POWER\n", port);
return -EPIPE;
case USB_PORT_FEAT_C_CONNECTION:
c67x00_ll_usb_clear_status(sie,
PORT_CONNECT_CHANGE(port));
len = 0;
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): OVER_CURRENT\n", port);
len = 0;
break;
case USB_PORT_FEAT_C_RESET:
dev_dbg(c67x00_hcd_dev(c67x00),
"ClearPortFeature (%d): C_RESET\n", port);
len = 0;
break;
default:
dev_dbg(c67x00_hcd_dev(c67x00),
"%s: ClearPortFeature %d (0x%04x) Error!\n",
__func__, port, wValue);
return -EPIPE;
}
break;
case GetHubDescriptor:
len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
memcpy(buf, c67x00_hub_des, len);
break;
default:
dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
return -EPIPE;
}
return 0;
}
/* ---------------------------------------------------------------------
* Main part of host controller driver
*/
/**
* c67x00_hcd_irq
*
* This function is called from the interrupt handler in c67x00-drv.c
*/
static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
{
struct c67x00_hcd *c67x00 = sie->private_data;
struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
/* Handle sie message flags */
if (msg) {
if (msg & HUSB_TDListDone)
c67x00_sched_kick(c67x00);
else
dev_warn(c67x00_hcd_dev(c67x00),
"Unknown SIE msg flag(s): 0x%04x\n", msg);
}
if (unlikely(hcd->state == HC_STATE_HALT))
return;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
return;
/* Handle Start of frame events */
if (int_status & SOFEOP_FLG(sie->sie_num)) {
c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
c67x00_sched_kick(c67x00);
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
}
/**
* c67x00_hcd_start: Host controller start hook
*/
static int c67x00_hcd_start(struct usb_hcd *hcd)
{
hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING;
hcd->poll_rh = 1;
return 0;
}
/**
* c67x00_hcd_stop: Host controller stop hook
*/
static void c67x00_hcd_stop(struct usb_hcd *hcd)
{
/* Nothing to do */
}
static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
{
struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
u16 temp_val;
dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
temp_val &= HOST_FRAME_MASK;
return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
}
static struct hc_driver c67x00_hc_driver = {
.description = "c67x00-hcd",
.product_desc = "Cypress C67X00 Host Controller",
.hcd_priv_size = sizeof(struct c67x00_hcd),
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.start = c67x00_hcd_start,
.stop = c67x00_hcd_stop,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = c67x00_urb_enqueue,
.urb_dequeue = c67x00_urb_dequeue,
.endpoint_disable = c67x00_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = c67x00_hcd_get_frame,
/*
* root hub support
*/
.hub_status_data = c67x00_hub_status_data,
.hub_control = c67x00_hub_control,
};
/* ---------------------------------------------------------------------
* Setup/Teardown routines
*/
int c67x00_hcd_probe(struct c67x00_sie *sie)
{
struct c67x00_hcd *c67x00;
struct usb_hcd *hcd;
unsigned long flags;
int retval;
if (usb_disabled())
return -ENODEV;
hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
if (!hcd) {
retval = -ENOMEM;
goto err0;
}
c67x00 = hcd_to_c67x00_hcd(hcd);
spin_lock_init(&c67x00->lock);
c67x00->sie = sie;
INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
c67x00->urb_count = 0;
INIT_LIST_HEAD(&c67x00->td_list);
c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
c67x00->max_frame_bw = MAX_FRAME_BW_STD;
c67x00_ll_husb_init_host_port(sie);
init_completion(&c67x00->endpoint_disable);
retval = c67x00_sched_start_scheduler(c67x00);
if (retval)
goto err1;
retval = usb_add_hcd(hcd, 0, 0);
if (retval) {
dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
__func__, retval);
goto err2;
}
spin_lock_irqsave(&sie->lock, flags);
sie->private_data = c67x00;
sie->irq = c67x00_hcd_irq;
spin_unlock_irqrestore(&sie->lock, flags);
return retval;
err2:
c67x00_sched_stop_scheduler(c67x00);
err1:
usb_put_hcd(hcd);
err0:
return retval;
}
/* may be called with controller, bus, and devices active */
void c67x00_hcd_remove(struct c67x00_sie *sie)
{
struct c67x00_hcd *c67x00 = sie->private_data;
struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
c67x00_sched_stop_scheduler(c67x00);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
}
/*
* c67x00-hcd.h: Cypress C67X00 USB HCD
*
* Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
#ifndef _USB_C67X00_HCD_H
#define _USB_C67X00_HCD_H
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/usb.h>
#include "../core/hcd.h"
#include "c67x00.h"
/*
* The following parameters depend on the CPU speed, bus speed, ...
* These can be tuned for specific use cases, e.g. if isochronous transfers
* are very important, bandwith can be sacrificed to guarantee that the
* 1ms deadline will be met.
* If bulk transfers are important, the MAX_FRAME_BW can be increased,
* but some (or many) isochronous deadlines might not be met.
*
* The values are specified in bittime.
*/
/*
* The current implementation switches between _STD (default) and _ISO (when
* isochronous transfers are scheduled), in order to optimize the throughput
* in normal cicrumstances, but also provide good isochronous behaviour.
*
* Bandwidth is described in bit time so with a 12MHz USB clock and 1ms
* frames; there are 12000 bit times per frame.
*/
#define TOTAL_FRAME_BW 12000
#define DEFAULT_EOT 2250
#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT)
#define MAX_FRAME_BW_ISO 2400
/*
* Periodic transfers may only use 90% of the full frame, but as
* we currently don't even use 90% of the full frame, we may
* use the full usable time for periodic transfers.
*/
#define MAX_PERIODIC_BW(full_bw) full_bw
/* -------------------------------------------------------------------------- */
struct c67x00_hcd {
spinlock_t lock;
struct c67x00_sie *sie;
unsigned int low_speed_ports; /* bitmask of low speed ports */
unsigned int urb_count;
unsigned int urb_iso_count;
struct list_head list[4]; /* iso, int, ctrl, bulk */
#if PIPE_BULK != 3
#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3"
#endif
/* USB bandwidth allocated to td_list */
int bandwidth_allocated;
/* USB bandwidth allocated for isoc/int transfer */
int periodic_bw_allocated;
struct list_head td_list;
int max_frame_bw;
u16 td_base_addr;
u16 buf_base_addr;
u16 next_td_addr;
u16 next_buf_addr;
struct tasklet_struct tasklet;
struct completion endpoint_disable;
u16 current_frame;
u16 last_frame;
};
static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd)
{
return (struct c67x00_hcd *)(hcd->hcd_priv);
}
static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
{
return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
}
/* ---------------------------------------------------------------------
* Functions used by c67x00-drv
*/
int c67x00_hcd_probe(struct c67x00_sie *sie);
void c67x00_hcd_remove(struct c67x00_sie *sie);
/* ---------------------------------------------------------------------
* Transfer Descriptor scheduling functions
*/
int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
void c67x00_endpoint_disable(struct usb_hcd *hcd,
struct usb_host_endpoint *ep);
void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg);
void c67x00_sched_kick(struct c67x00_hcd *c67x00);
int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
#endif /* _USB_C67X00_HCD_H */
/*
* c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
*
* Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
#include <asm/byteorder.h>
#include <linux/io.h>
#include <linux/usb/c67x00.h>
#include "c67x00.h"
#define COMM_REGS 14
struct c67x00_lcp_int_data {
u16 regs[COMM_REGS];
};
/* -------------------------------------------------------------------------- */
/* Interface definitions */
#define COMM_ACK 0x0FED
#define COMM_NAK 0xDEAD
#define COMM_RESET 0xFA50
#define COMM_EXEC_INT 0xCE01
#define COMM_INT_NUM 0x01C2
/* Registers 0 to COMM_REGS-1 */
#define COMM_R(x) (0x01C4 + 2 * (x))
#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0)
#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6)
#define HUSB_pEOT 0x01B4
/* Software interrupts */
/* 114, 115: */
#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072)
#define HUSB_RESET_INT 0x0074
#define SUSB_INIT_INT 0x0071
#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2)
/* -----------------------------------------------------------------------
* HPI implementation
*
* The c67x00 chip also support control via SPI or HSS serial
* interfaces. However, this driver assumes that register access can
* be performed from IRQ context. While this is a safe assuption with
* the HPI interface, it is not true for the serial interfaces.
*/
/* HPI registers */
#define HPI_DATA 0
#define HPI_MAILBOX 1
#define HPI_ADDR 2
#define HPI_STATUS 3
static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
{
return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
}
static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
{
__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
}
static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
{
hpi_write_reg(dev, HPI_ADDR, reg);
return hpi_read_reg(dev, HPI_DATA);
}
static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
{
u16 value;
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
{
hpi_write_reg(dev, HPI_ADDR, reg);
hpi_write_reg(dev, HPI_DATA, value);
}
static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
{
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_word_nolock(dev, reg, value);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
/*
* Only data is little endian, addr has cpu endianess
*/
static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
u16 *data, u16 count)
{
unsigned long flags;
int i;
spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
/*
* Only data is little endian, addr has cpu endianess
*/
static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
u16 *data, u16 count)
{
unsigned long flags;
int i;
spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
*data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
{
u16 value;
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
hpi_write_word_nolock(dev, reg, value | mask);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
{
u16 value;
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
hpi_write_word_nolock(dev, reg, value & ~mask);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static u16 hpi_recv_mbox(struct c67x00_device *dev)
{
u16 value;
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_reg(dev, HPI_MAILBOX);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
{
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_MAILBOX, value);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
{
u16 value;
unsigned long flags;
spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_reg(dev, HPI_STATUS);
spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
{
int i;
hpi_recv_mbox(dev);
c67x00_ll_hpi_status(dev);
hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
for (i = 0; i < C67X00_SIES; i++) {
hpi_write_word(dev, SIEMSG_REG(i), 0);
hpi_read_word(dev, SIEMSG_REG(i));
}
}
void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
{
hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
SOFEOP_TO_HPI_EN(sie->sie_num));
}
void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
{
hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
SOFEOP_TO_HPI_EN(sie->sie_num));
}
/* -------------------------------------------------------------------------- */
/* Transactions */
static inline u16 ll_recv_msg(struct c67x00_device *dev)
{
u16 res;
res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
WARN_ON(!res);
return (res == 0) ? -EIO : 0;
}
/* -------------------------------------------------------------------------- */
/* General functions */
u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
{
u16 val;
val = hpi_read_word(dev, SIEMSG_REG(sie_num));
/* clear register to allow next message */
hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
return val;
}
u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
{
return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
}
/**
* c67x00_ll_usb_clear_status - clear the USB status bits
*/
void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
{
hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
}
u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
{
return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
}
/* -------------------------------------------------------------------------- */
static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
struct c67x00_lcp_int_data *data)
{
int i, rc;
mutex_lock(&dev->hpi.lcp.mutex);
hpi_write_word(dev, COMM_INT_NUM, nr);
for (i = 0; i < COMM_REGS; i++)
hpi_write_word(dev, COMM_R(i), data->regs[i]);
hpi_send_mbox(dev, COMM_EXEC_INT);
rc = ll_recv_msg(dev);
mutex_unlock(&dev->hpi.lcp.mutex);
return rc;
}
/* -------------------------------------------------------------------------- */
/* Host specific functions */
void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
{
mutex_lock(&dev->hpi.lcp.mutex);
hpi_write_word(dev, HUSB_pEOT, value);
mutex_unlock(&dev->hpi.lcp.mutex);
}
static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
{
struct c67x00_device *dev = sie->dev;
struct c67x00_lcp_int_data data;
int rc;
rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
BUG_ON(rc); /* No return path for error code; crash spectacularly */
}
void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
{
struct c67x00_device *dev = sie->dev;
struct c67x00_lcp_int_data data;
int rc;
data.regs[0] = 50; /* Reset USB port for 50ms */
data.regs[1] = port | (sie->sie_num << 1);
rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
BUG_ON(rc); /* No return path for error code; crash spectacularly */
}
void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
{
hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
}
u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
{
return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
}
u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
{
return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
}
void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
{
/* Set port into host mode */
hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
c67x00_ll_husb_sie_init(sie);
/* Clear interrupts */
c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
/* Check */
if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
dev_warn(sie_dev(sie),
"SIE %d not set to host mode\n", sie->sie_num);
}
void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
{
/* Clear connect change */
c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
/* Enable interrupts */
hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
SOFEOP_TO_CPU_EN(sie->sie_num));
hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
SOF_EOP_IRQ_EN | DONE_IRQ_EN);
/* Enable pull down transistors */
hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
}
/* -------------------------------------------------------------------------- */
void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
{
if ((int_status & MBX_OUT_FLG) == 0)
return;
dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
complete(&dev->hpi.lcp.msg_received);
}
/* -------------------------------------------------------------------------- */
int c67x00_ll_reset(struct c67x00_device *dev)
{
int rc;
mutex_lock(&dev->hpi.lcp.mutex);
hpi_send_mbox(dev, COMM_RESET);
rc = ll_recv_msg(dev);
mutex_unlock(&dev->hpi.lcp.mutex);
return rc;
}
/* -------------------------------------------------------------------------- */
/**
* c67x00_ll_write_mem_le16 - write into c67x00 memory
* Only data is little endian, addr has cpu endianess.
*/
void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
void *data, int len)
{
u8 *buf = data;
/* Sanity check */
if (addr + len > 0xffff) {
dev_err(&dev->pdev->dev,
"Trying to write beyond writable region!\n");
return;
}
if (addr & 0x01) {
/* unaligned access */
u16 tmp;
tmp = hpi_read_word(dev, addr - 1);
tmp = (tmp & 0x00ff) | (*buf++ << 8);
hpi_write_word(dev, addr - 1, tmp);
addr++;
len--;
}
hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
if (len) {
u16 tmp;
tmp = hpi_read_word(dev, addr);
tmp = (tmp & 0xff00) | *buf;
hpi_write_word(dev, addr, tmp);
}
}
/**
* c67x00_ll_read_mem_le16 - read from c67x00 memory
* Only data is little endian, addr has cpu endianess.
*/
void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
void *data, int len)
{
u8 *buf = data;
if (addr & 0x01) {
/* unaligned access */
u16 tmp;
tmp = hpi_read_word(dev, addr - 1);
*buf++ = (tmp >> 8) & 0x00ff;
addr++;
len--;
}
hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
if (len) {
u16 tmp;
tmp = hpi_read_word(dev, addr);
*buf = tmp & 0x00ff;
}
}
/* -------------------------------------------------------------------------- */
void c67x00_ll_init(struct c67x00_device *dev)
{
mutex_init(&dev->hpi.lcp.mutex);
init_completion(&dev->hpi.lcp.msg_received);
}
void c67x00_ll_release(struct c67x00_device *dev)
{
}
此差异已折叠。
/*
* c67x00.h: Cypress C67X00 USB register and field definitions
*
* Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
#ifndef _USB_C67X00_H
#define _USB_C67X00_H
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/mutex.h>
/* ---------------------------------------------------------------------
* Cypress C67x00 register definitions
*/
/* Hardware Revision Register */
#define HW_REV_REG 0xC004
/* General USB registers */
/* ===================== */
/* USB Control Register */
#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A)
#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400)
#define HOST_MODE 0x0200
#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080)
#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001)
/* USB status register - Notice it has different content in hcd/udc mode */
#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090)
#define EP0_IRQ_FLG 0x0001
#define EP1_IRQ_FLG 0x0002
#define EP2_IRQ_FLG 0x0004
#define EP3_IRQ_FLG 0x0008
#define EP4_IRQ_FLG 0x0010
#define EP5_IRQ_FLG 0x0020
#define EP6_IRQ_FLG 0x0040
#define EP7_IRQ_FLG 0x0080
#define RESET_IRQ_FLG 0x0100
#define SOF_EOP_IRQ_FLG 0x0200
#define ID_IRQ_FLG 0x4000
#define VBUS_IRQ_FLG 0x8000
/* USB Host only registers */
/* ======================= */
/* Host n Control Register */
#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080)
#define PREAMBLE_EN 0x0080 /* Preamble enable */
#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */
#define ISO_EN 0x0010 /* Isochronous enable */
#define ARM_EN 0x0001 /* Arm operation */
/* Host n Interrupt Enable Register */
#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */
#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */
#define ID_IRQ_EN 0x4000 /* ID interrupt enable */
#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */
#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */
/* USB status register */
#define HOST_STAT_MASK 0x02FD
#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004)
/* Host Frame Register */
#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096)
#define HOST_FRAME_MASK 0x07FF
/* USB Peripheral only registers */
/* ============================= */
/* Device n Port Sel reg */
#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084)
/* Device n Interrupt Enable Register */
#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \
? (0x0280 + (ep << 4)) \
: (0x0200 + (ep << 4)))
#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \
? (0x0286 + (ep << 4)) \
: (0x0206 + (ep << 4)))
#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E))
/* HPI registers */
/* ============= */
/* HPI Status register */
#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10))
#define SIEMSG_FLG(x) (1 << (4 + (x)))
#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002)
#define DONE_FLG(x) (1 << (2 + (x)))
#define RESUME_FLG(x) (1 << (6 + (x)))
#define MBX_OUT_FLG 0x0001 /* Message out available */
#define MBX_IN_FLG 0x0100
#define ID_FLG 0x4000
#define VBUS_FLG 0x8000
/* Interrupt routing register */
#define HPI_IRQ_ROUTING_REG 0x0142
#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001)
#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004)
#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040)
#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800)
#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400)
#define ID_TO_HPI_ENABLE 0x4000
#define VBUS_TO_HPI_ENABLE 0x8000
/* SIE msg registers */
#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144)
#define HUSB_TDListDone 0x1000
#define SUSB_EP0_MSG 0x0001
#define SUSB_EP1_MSG 0x0002
#define SUSB_EP2_MSG 0x0004
#define SUSB_EP3_MSG 0x0008
#define SUSB_EP4_MSG 0x0010
#define SUSB_EP5_MSG 0x0020
#define SUSB_EP6_MSG 0x0040
#define SUSB_EP7_MSG 0x0080
#define SUSB_RST_MSG 0x0100
#define SUSB_SOF_MSG 0x0200
#define SUSB_CFG_MSG 0x0400
#define SUSB_SUS_MSG 0x0800
#define SUSB_ID_MSG 0x4000
#define SUSB_VBUS_MSG 0x8000
/* BIOS interrupt routines */
#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81)
#define SUSBx_SEND_INT(x) ((x) ? 96 : 80)
#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4)
#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */
#define SIE_TD_SIZE 0x200 /* size of the td list */
#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */
#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
#define CY_UDC_REQ_HEADER_BASE 0x1100
/* 8- byte request headers for IN/OUT transfers */
#define CY_UDC_REQ_HEADER_SIZE 8
#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
((ep_num) * CY_UDC_REQ_HEADER_SIZE))
#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8))
#define CY_UDC_BIOS_REPLACE_BASE 0x1800
#define CY_UDC_REQ_BUFFER_BASE 0x2000
#define CY_UDC_REQ_BUFFER_SIZE 0x0400
#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
/* ---------------------------------------------------------------------
* Driver data structures
*/
struct c67x00_device;
/**
* struct c67x00_sie - Common data associated with a SIE
* @lock: lock to protect this struct and the associated chip registers
* @private_data: subdriver dependent data
* @irq: subdriver dependent irq handler, set NULL when not used
* @dev: link to common driver structure
* @sie_num: SIE number on chip, starting from 0
* @mode: SIE mode (host/peripheral/otg/not used)
*/
struct c67x00_sie {
/* Entries to be used by the subdrivers */
spinlock_t lock; /* protect this structure */
void *private_data;
void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
/* Read only: */
struct c67x00_device *dev;
int sie_num;
int mode;
};
#define sie_dev(s) (&(s)->dev->pdev->dev)
/**
* struct c67x00_lcp
*/
struct c67x00_lcp {
/* Internal use only */
struct mutex mutex;
struct completion msg_received;
u16 last_msg;
};
/*
* struct c67x00_hpi
*/
struct c67x00_hpi {
void __iomem *base;
int regstep;
spinlock_t lock;
struct c67x00_lcp lcp;
};
#define C67X00_SIES 2
#define C67X00_PORTS 2
/**
* struct c67x00_device - Common data associated with a c67x00 instance
* @hpi: hpi addresses
* @sie: array of sie's on this chip
* @pdev: platform device of instance
* @pdata: configuration provided by the platform
*/
struct c67x00_device {
struct c67x00_hpi hpi;
struct c67x00_sie sie[C67X00_SIES];
struct platform_device *pdev;
struct c67x00_platform_data *pdata;
};
/* ---------------------------------------------------------------------
* Low level interface functions
*/
/* Host Port Interface (HPI) functions */
u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
/* General functions */
u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
void *data, int len);
void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
void *data, int len);
/* Host specific functions */
void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
/* Called by c67x00_irq to handle lcp interrupts */
void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
/* Setup and teardown */
void c67x00_ll_init(struct c67x00_device *dev);
void c67x00_ll_release(struct c67x00_device *dev);
int c67x00_ll_reset(struct c67x00_device *dev);
#endif /* _USB_C67X00_H */
......@@ -394,7 +394,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
if (!io->urbs)
goto nomem;
urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
urb_flags = URB_NO_INTERRUPT;
if (dma)
urb_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
......
......@@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592
However, this problem is improved if change a value of
NET_IP_ALIGN to 4.
config USB_GADGET_PXA27X
boolean "PXA 27x"
depends on ARCH_PXA && PXA27x
help
Intel's PXA 27x series XScale ARM v5TE processors include
an integrated full speed USB 1.1 device controller.
It has up to 23 endpoints, as well as endpoint zero (for
control transfers).
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "pxa27x_udc" and force all
gadget drivers to also be dynamically linked.
config USB_PXA27X
tristate
depends on USB_GADGET_PXA27X
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
......
......@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
......
......@@ -235,10 +235,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_PXA27X
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
......@@ -270,6 +266,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
#ifdef CONFIG_USB_GADGET_PXA27X
#define DEV_CONFIG_SUBSET
#endif
#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
......
......@@ -2307,6 +2307,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
return rc;
}
static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
{
int rc;
DBG(fsg, "bulk-in set wedge\n");
rc = usb_ep_set_wedge(fsg->bulk_in);
if (rc == -EAGAIN)
VDBG(fsg, "delayed bulk-in endpoint wedge\n");
while (rc != 0) {
if (rc != -EAGAIN) {
WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
rc = 0;
break;
}
/* Wait for a short time and then try again */
if (msleep_interruptible(100) != 0)
return -EINTR;
rc = usb_ep_set_wedge(fsg->bulk_in);
}
return rc;
}
static int pad_with_zeros(struct fsg_dev *fsg)
{
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
......@@ -2957,7 +2980,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
* We aren't required to halt the OUT endpoint; instead
* we can simply accept and discard any data received
* until the next reset. */
halt_bulk_in_endpoint(fsg);
wedge_bulk_in_endpoint(fsg);
set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
}
......
此差异已折叠。
/*
* linux/drivers/usb/gadget/pxa27x_udc.h
* Intel PXA27x on-chip full speed USB device controller
*
* Inspired by original driver by Frank Becker, David Brownell, and others.
* Copyright (C) 2008 Robert Jarzmik
*
* 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
*/
#ifndef __LINUX_USB_GADGET_PXA27X_H
#define __LINUX_USB_GADGET_PXA27X_H
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/io.h>
/*
* Register definitions
*/
/* Offsets */
#define UDCCR 0x0000 /* UDC Control Register */
#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */
#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */
#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */
#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */
#define UDCFNR 0x0014 /* UDC Frame Number Register */
#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */
#define UP2OCR 0x0020 /* USB Port 2 Output Control register */
#define UP3OCR 0x0024 /* USB Port 3 Output Control register */
#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */
#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */
#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */
#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */
#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */
#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation
Protocol Port Support */
#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol
Support */
#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol
Enable */
#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */
#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */
#define UDCCR_ACN_S 11
#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */
#define UDCCR_AIN_S 8
#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface
Setting Number */
#define UDCCR_AAISN_S 5
#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active
Configuration */
#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration
Error */
#define UDCCR_UDR (1 << 2) /* UDC Resume */
#define UDCCR_UDA (1 << 1) /* UDC Active */
#define UDCCR_UDE (1 << 0) /* UDC Enable */
#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */
#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */
#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */
#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */
#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */
#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */
#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */
#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */
#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt
Rising Edge Interrupt Enable */
#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt
Falling Edge Interrupt Enable */
#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge
Interrupt Enable */
#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge
Interrupt Enable */
#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge
Interrupt Enable */
#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge
Interrupt Enable */
#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge
Interrupt Enable */
#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge
Interrupt Enable */
#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising
Edge Interrupt Enable */
#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling
Edge Interrupt Enable */
#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge
Interrupt Enable */
#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
Interrupt Enable */
/* Host Port 2 field bits */
#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */
#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */
/* Transceiver enablers */
#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */
#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */
#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */
#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */
#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */
#define UP2OCR_DMPUBE (1 << 7) /* D- Pull Up Bypass Enable */
#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */
#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */
#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */
#define UP2OCR_HXS (1 << 16) /* Transceiver Output Select */
#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */
#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
#define UDCCSR0_SA (1 << 7) /* Setup Active */
#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
#define UDCCSR0_FST (1 << 5) /* Force Stall */
#define UDCCSR0_SST (1 << 4) /* Sent Stall */
#define UDCCSR0_DME (1 << 3) /* DMA Enable */
#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */
#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */
#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */
#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */
#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */
#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */
#define UDCCSR_FST (1 << 5) /* Force STALL */
#define UDCCSR_SST (1 << 4) /* Sent STALL */
#define UDCCSR_DME (1 << 3) /* DMA Enable */
#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
#define UDCCSR_PC (1 << 1) /* Packet Complete */
#define UDCCSR_FS (1 << 0) /* FIFO needs service */
#define UDCCONR_CN (0x03 << 25) /* Configuration Number */
#define UDCCONR_CN_S 25
#define UDCCONR_IN (0x07 << 22) /* Interface Number */
#define UDCCONR_IN_S 22
#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */
#define UDCCONR_AISN_S 19
#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */
#define UDCCONR_EN_S 15
#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */
#define UDCCONR_ET_S 13
#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */
#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */
#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */
#define UDCCONR_ET_NU (0x00 << 13) /* Not used */
#define UDCCONR_ED (1 << 12) /* Endpoint Direction */
#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */
#define UDCCONR_MPS_S 2
#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */
#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE)
#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST)
#define UDC_FNR_MASK (0x7ff)
#define UDC_BCR_MASK (0x3ff)
/*
* UDCCR = UDC Endpoint Configuration Registers
* UDCCSR = UDC Control/Status Register for this EP
* UDCBCR = UDC Byte Count Remaining (contents of OUT fifo)
* UDCDR = UDC Endpoint Data Register (the fifo)
*/
#define ofs_UDCCR(ep) (UDCCRn(ep->idx))
#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx))
#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx))
#define ofs_UDCDR(ep) (UDCDRn(ep->idx))
/* Register access macros */
#define udc_ep_readl(ep, reg) \
__raw_readl((ep)->dev->regs + ofs_##reg(ep))
#define udc_ep_writel(ep, reg, value) \
__raw_writel((value), ep->dev->regs + ofs_##reg(ep))
#define udc_ep_readb(ep, reg) \
__raw_readb((ep)->dev->regs + ofs_##reg(ep))
#define udc_ep_writeb(ep, reg, value) \
__raw_writeb((value), ep->dev->regs + ofs_##reg(ep))
#define udc_readl(dev, reg) \
__raw_readl((dev)->regs + (reg))
#define udc_writel(udc, reg, value) \
__raw_writel((value), (udc)->regs + (reg))
#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME)
#define UDCCISR0_EP_MASK ~0
#define UDCCISR1_EP_MASK 0xffff
#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)
#define EPIDX(ep) (ep->idx)
#define EPADDR(ep) (ep->addr)
#define EPXFERTYPE(ep) (ep->type)
#define EPNAME(ep) (ep->name)
#define is_ep0(ep) (!ep->idx)
#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC)
/*
* Endpoint definitions
*
* Once enabled, pxa endpoint configuration is freezed, and cannot change
* unless a reset happens or the udc is disabled.
* Therefore, we must define all pxa potential endpoint definitions needed for
* all gadget and set them up before the udc is enabled.
*
* As the architecture chosen is fully static, meaning the pxa endpoint
* configurations are set up once and for all, we must provide a way to match
* one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget
* layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt)
* criteria, while the pxa architecture requires that.
*
* The solution is to define several pxa endpoints matching one usb_ep. Ex:
* - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when
* the udc talks on (config=3, interface=0, alt=0)
* - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when
* the udc talks on (config=3, interface=0, alt=1)
* - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when
* the udc talks on (config=2, interface=0, alt=0)
*
* We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...)
*/
/*
* Endpoint definition helpers
*/
#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
.desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
.bmAttributes = type, \
.wMaxPacketSize = maxpkt, }, \
.dev = &memory \
}
#define USB_EP_BULK(addr, bname, dir) \
USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
#define USB_EP_ISO(addr, bname, dir) \
USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
#define USB_EP_INT(addr, bname, dir) \
USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1)
#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0)
#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1)
#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0)
#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1)
#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE)
#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
{ \
.dev = &memory, \
.name = "ep" #_idx, \
.idx = _idx, .enabled = 0, \
.dir_in = dir, .addr = _addr, \
.config = _config, .interface = iface, .alternate = altset, \
.type = _type, .fifo_size = maxpkt, \
}
#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \
PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \
config, iface, alt)
#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \
PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \
config, iface, alt)
#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \
PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \
config, iface, alt)
#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a)
#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a)
#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a)
#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a)
#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a)
#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
struct pxa27x_udc;
struct stats {
unsigned long in_ops;
unsigned long out_ops;
unsigned long in_bytes;
unsigned long out_bytes;
unsigned long irqs;
};
/**
* struct udc_usb_ep - container of each usb_ep structure
* @usb_ep: usb endpoint
* @desc: usb descriptor, especially type and address
* @dev: udc managing this endpoint
* @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call)
*/
struct udc_usb_ep {
struct usb_ep usb_ep;
struct usb_endpoint_descriptor desc;
struct pxa_udc *dev;
struct pxa_ep *pxa_ep;
};
/**
* struct pxa_ep - pxa endpoint
* @dev: udc device
* @queue: requests queue
* @lock: lock to pxa_ep data (queues and stats)
* @enabled: true when endpoint enabled (not stopped by gadget layer)
* @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
* @name: endpoint name (for trace/debug purpose)
* @dir_in: 1 if IN endpoint, 0 if OUT endpoint
* @addr: usb endpoint number
* @config: configuration in which this endpoint is active
* @interface: interface in which this endpoint is active
* @alternate: altsetting in which this endpoitn is active
* @fifo_size: max packet size in the endpoint fifo
* @type: endpoint type (bulk, iso, int, ...)
* @udccsr_value: save register of UDCCSR0 for suspend/resume
* @udccr_value: save register of UDCCR for suspend/resume
* @stats: endpoint statistics
*
* The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned
* (cares about config/interface/altsetting, thus placing needless limits on
* device capability) and full of implementation bugs forcing it to be set up
* for use more or less like a pxa255.
*
* As we define the pxa_ep statically, we must guess all needed pxa_ep for all
* gadget which may work with this udc driver.
*/
struct pxa_ep {
struct pxa_udc *dev;
struct list_head queue;
spinlock_t lock; /* Protects this structure */
/* (queues, stats) */
unsigned enabled:1;
unsigned idx:5;
char *name;
/*
* Specific pxa endpoint data, needed for hardware initialization
*/
unsigned dir_in:1;
unsigned addr:3;
unsigned config:2;
unsigned interface:3;
unsigned alternate:3;
unsigned fifo_size;
unsigned type;
#ifdef CONFIG_PM
u32 udccsr_value;
u32 udccr_value;
#endif
struct stats stats;
};
/**
* struct pxa27x_request - container of each usb_request structure
* @req: usb request
* @udc_usb_ep: usb endpoint the request was submitted on
* @in_use: sanity check if request already queued on an pxa_ep
* @queue: linked list of requests, linked on pxa_ep->queue
*/
struct pxa27x_request {
struct usb_request req;
struct udc_usb_ep *udc_usb_ep;
unsigned in_use:1;
struct list_head queue;
};
enum ep0_state {
WAIT_FOR_SETUP,
SETUP_STAGE,
IN_DATA_STAGE,
OUT_DATA_STAGE,
IN_STATUS_STAGE,
OUT_STATUS_STAGE,
STALL,
WAIT_ACK_SET_CONF_INTERF
};
static char *ep0_state_name[] = {
"WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE",
"IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL",
"WAIT_ACK_SET_CONF_INTERF"
};
#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state]
#define EP0_FIFO_SIZE 16U
#define BULK_FIFO_SIZE 64U
#define ISO_FIFO_SIZE 256U
#define INT_FIFO_SIZE 16U
struct udc_stats {
unsigned long irqs_reset;
unsigned long irqs_suspend;
unsigned long irqs_resume;
unsigned long irqs_reconfig;
};
#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */
#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */
/**
* struct pxa_udc - udc structure
* @regs: mapped IO space
* @irq: udc irq
* @clk: udc clock
* @usb_gadget: udc gadget structure
* @driver: bound gadget (zero, g_ether, g_file_storage, ...)
* @dev: device
* @mach: machine info, used to activate specific GPIO
* @ep0state: control endpoint state machine state
* @stats: statistics on udc usage
* @udc_usb_ep: array of usb endpoints offered by the gadget
* @pxa_ep: array of pxa available endpoints
* @config: UDC active configuration
* @last_interface: UDC interface of the last SET_INTERFACE host request
* @last_alternate: UDC altsetting of the last SET_INTERFACE host request
* @udccsr0: save of udccsr0 in case of suspend
* @debugfs_root: root entry of debug filesystem
* @debugfs_state: debugfs entry for "udcstate"
* @debugfs_queues: debugfs entry for "queues"
* @debugfs_eps: debugfs entry for "epstate"
*/
struct pxa_udc {
void __iomem *regs;
int irq;
struct clk *clk;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct device *dev;
struct pxa2xx_udc_mach_info *mach;
enum ep0_state ep0state;
struct udc_stats stats;
struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS];
struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS];
unsigned config:2;
unsigned last_interface:3;
unsigned last_alternate:3;
#ifdef CONFIG_PM
unsigned udccsr0;
#endif
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
struct dentry *debugfs_state;
struct dentry *debugfs_queues;
struct dentry *debugfs_eps;
#endif
};
static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
{
return container_of(gadget, struct pxa_udc, gadget);
}
/*
* Debugging/message support
*/
#define ep_dbg(ep, fmt, arg...) \
dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
#define ep_vdbg(ep, fmt, arg...) \
dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
#define ep_err(ep, fmt, arg...) \
dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
#define ep_info(ep, fmt, arg...) \
dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
#define ep_warn(ep, fmt, arg...) \
dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
#endif /* __LINUX_USB_GADGET_PXA27X_H */
......@@ -135,7 +135,10 @@ struct gs_port {
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
struct gs_buf *port_write_buf;
struct usb_cdc_line_coding port_line_coding;
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
u16 port_handshake_bits;
#define RS232_RTS (1 << 1)
#define RS232_DTE (1 << 0)
};
/* the device structure holds info for the USB device */
......@@ -199,6 +202,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
static int gs_setup_class(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl);
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
......@@ -406,7 +411,7 @@ static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
.bmCapabilities = 0,
.bmCapabilities = (1 << 1),
};
static const struct usb_cdc_union_desc gs_union_desc = {
......@@ -1502,6 +1507,8 @@ static int gs_setup(struct usb_gadget *gadget,
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
req->complete = gs_setup_complete;
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
ret = gs_setup_standard(gadget,ctrl);
......@@ -1679,18 +1686,14 @@ static int gs_setup_class(struct usb_gadget *gadget,
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
/* FIXME Submit req to read the data; have its completion
* handler copy that data to port->port_line_coding (iff
* it's valid) and maybe pass it on. Until then, fail.
*/
pr_warning("gs_setup: set_line_coding "
"unuspported\n");
if (wLength != sizeof(struct usb_cdc_line_coding))
break;
ret = wLength;
req->complete = gs_setup_complete_set_line_coding;
break;
case USB_CDC_REQ_GET_LINE_CODING:
port = dev->dev_port[0]; /* ACM only has one port */
ret = min(wLength,
(u16)sizeof(struct usb_cdc_line_coding));
ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
memcpy(req->buf, &port->port_line_coding, ret);
......@@ -1699,15 +1702,27 @@ static int gs_setup_class(struct usb_gadget *gadget,
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
/* FIXME Submit req to read the data; have its completion
* handler use that to set the state (iff it's valid) and
* maybe pass it on. Until then, fail.
*/
pr_warning("gs_setup: set_control_line_state "
"unuspported\n");
if (wLength != 0)
break;
ret = 0;
if (port) {
/* REVISIT: we currently just remember this data.
* If we change that, update whatever hardware needs
* updating.
*/
spin_lock(&port->port_lock);
port->port_handshake_bits = wValue;
spin_unlock(&port->port_lock);
}
break;
default:
/* NOTE: strictly speaking, we should accept AT-commands
* using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
* But our call management descriptor says we don't handle
* call management, so we should be able to get by without
* handling those "required" commands (except by stalling).
*/
pr_err("gs_setup: unknown class request, "
"type=%02x, request=%02x, value=%04x, "
"index=%04x, length=%d\n",
......@@ -1719,6 +1734,42 @@ static int gs_setup_class(struct usb_gadget *gadget,
return ret;
}
static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
struct usb_request *req)
{
struct gs_dev *dev = ep->driver_data;
struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
switch (req->status) {
case 0:
/* normal completion */
if (req->actual != sizeof(port->port_line_coding))
usb_ep_set_halt(ep);
else if (port) {
struct usb_cdc_line_coding *value = req->buf;
/* REVISIT: we currently just remember this data.
* If we change that, (a) validate it first, then
* (b) update whatever hardware needs updating.
*/
spin_lock(&port->port_lock);
port->port_line_coding = *value;
spin_unlock(&port->port_lock);
}
break;
case -ESHUTDOWN:
/* disconnect */
gs_free_req(ep, req);
break;
default:
/* unexpected */
break;
}
return;
}
/*
* gs_setup_complete
*/
......@@ -1906,6 +1957,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
}
/* REVISIT the ACM mode should be able to actually *issue* some
* notifications, for at least serial state change events if
* not also for network connection; say so in bmCapabilities.
*/
pr_info("gs_set_config: %s configured, %s speed %s config\n",
GS_LONG_NAME,
gadget->speed == USB_SPEED_HIGH ? "high" : "full",
......
此差异已折叠。
......@@ -4,6 +4,19 @@
comment "USB Host Controller Drivers"
depends on USB
config USB_C67X00_HCD
tristate "Cypress C67x00 HCD support"
depends on USB
help
The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
host/peripheral/OTG USB controllers.
Enable this option to support this chip in host controller mode.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called c67x00.
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB && USB_ARCH_HAS_EHCI
......@@ -95,6 +108,32 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
config USB_ISP1760_HCD
tristate "ISP 1760 HCD support"
depends on USB && EXPERIMENTAL
---help---
The ISP1760 chip is a USB 2.0 host controller.
This driver does not support isochronous transfers or OTG.
To compile this driver as a module, choose M here: the
module will be called isp1760-hcd.
config USB_ISP1760_PCI
bool "Support for the PCI bus"
depends on USB_ISP1760_HCD && PCI
---help---
Enables support for the device present on the PCI bus.
This should only be required if you happen to have the eval kit from
NXP and you are going to test it.
config USB_ISP1760_OF
bool "Support for the OF platform bus"
depends on USB_ISP1760_HCD && OF
---help---
Enables support for the device present on the PowerPC
OpenFirmware platform bus.
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
......
......@@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
isp1760-objs := isp1760-hcd.o isp1760-if.o
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
......@@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
此差异已折叠。
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
/* exports for if */
struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
u64 irqflags, struct device *dev, const char *busname);
int init_kmem_once(void);
void deinit_kmem_cache(void);
/* EHCI capability registers */
#define HC_CAPLENGTH 0x00
#define HC_HCSPARAMS 0x04
#define HC_HCCPARAMS 0x08
/* EHCI operational registers */
#define HC_USBCMD 0x20
#define HC_USBSTS 0x24
#define HC_FRINDEX 0x2c
#define HC_CONFIGFLAG 0x60
#define HC_PORTSC1 0x64
#define HC_ISO_PTD_DONEMAP_REG 0x130
#define HC_ISO_PTD_SKIPMAP_REG 0x134
#define HC_ISO_PTD_LASTPTD_REG 0x138
#define HC_INT_PTD_DONEMAP_REG 0x140
#define HC_INT_PTD_SKIPMAP_REG 0x144
#define HC_INT_PTD_LASTPTD_REG 0x148
#define HC_ATL_PTD_DONEMAP_REG 0x150
#define HC_ATL_PTD_SKIPMAP_REG 0x154
#define HC_ATL_PTD_LASTPTD_REG 0x158
/* Configuration Register */
#define HC_HW_MODE_CTRL 0x300
#define ALL_ATX_RESET (1 << 31)
#define HW_DATA_BUS_32BIT (1 << 8)
#define HW_DACK_POL_HIGH (1 << 6)
#define HW_DREQ_POL_HIGH (1 << 5)
#define HW_INTR_HIGH_ACT (1 << 2)
#define HW_INTR_EDGE_TRIG (1 << 1)
#define HW_GLOBAL_INTR_EN (1 << 0)
#define HC_CHIP_ID_REG 0x304
#define HC_SCRATCH_REG 0x308
#define HC_RESET_REG 0x30c
#define SW_RESET_RESET_HC (1 << 1)
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
#define ATL_BUFFER 0x1
#define INT_BUFFER 0x2
#define ISO_BUFFER 0x4
#define BUFFER_MAP 0x7
#define HC_MEMORY_REG 0x33c
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
#define PORT1_INIT2 (1 << 23)
/* Interrupt Register */
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31C
#define HC_ATL_IRQ_MASK_OR_REG 0x320
#define HC_ISO_IRQ_MASK_AND_REG 0x324
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32C
/* Register sets */
#define HC_BEGIN_OF_ATL 0x0c00
#define HC_BEGIN_OF_INT 0x0800
#define HC_BEGIN_OF_ISO 0x0400
#define HC_BEGIN_OF_PAYLOAD 0x1000
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
#define ATL_REGS_OFFSET (0xc00)
#define INT_REGS_OFFSET (0x800)
/* Philips Transfer Descriptor (PTD) */
struct ptd {
__le32 dw0;
__le32 dw1;
__le32 dw2;
__le32 dw3;
__le32 dw4;
__le32 dw5;
__le32 dw6;
__le32 dw7;
};
struct inter_packet_info {
void *data_buffer;
u32 payload;
#define PTD_FIRE_NEXT (1 << 0)
#define PTD_URB_FINISHED (1 << 1)
struct urb *urb;
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
};
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
#define isp1760_info(priv, fmt, args...) \
dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
#define isp1760_err(priv, fmt, args...) \
dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
/* chip memory management */
struct memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
/*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
#define BLOCK_1_NUM 32
#define BLOCK_2_NUM 20
#define BLOCK_3_NUM 4
#define BLOCK_1_SIZE 256
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define PAYLOAD_SIZE 0xf000
/* I saw if some reloads if the pointer was negative */
#define ISP1760_NULL_POINTER (0x400)
/* ATL */
/* DW0 */
#define PTD_VALID 1
#define PTD_LENGTH(x) (((u32) x) << 3)
#define PTD_MAXPACKET(x) (((u32) x) << 18)
#define PTD_MULTI(x) (((u32) x) << 29)
#define PTD_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
#define PTD_PID_TOKEN(x) (((u32) x) << 10)
#define PTD_TRANS_BULK ((u32) 2 << 12)
#define PTD_TRANS_INT ((u32) 3 << 12)
#define PTD_TRANS_SPLIT ((u32) 1 << 14)
#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
#define PTD_PORT_NUM(x) (((u32) x) << 18)
#define PTD_HUB_NUM(x) (((u32) x) << 25)
#define PTD_PING(x) (((u32) x) << 26)
/* DW2 */
#define PTD_RL_CNT(x) (((u32) x) << 25)
#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
#define BASE_ADDR 0x1000
/* DW3 */
#define PTD_CERR(x) (((u32) x) << 23)
#define PTD_NAC_CNT(x) (((u32) x) << 19)
#define PTD_ACTIVE ((u32) 1 << 31)
#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ERROR_BIT (1 << 28)
#define DW3_QTD_ACTIVE (1 << 31)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
#define DATA_TOGGLE (1 << 31)
#define GET_DATA_TOGGLE(x) ((x) >> 31)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
#define HC_ATL_PL_SIZE (8192)
#endif
此差异已折叠。
......@@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci);
static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
u32 temp;
u32 temp = 0;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
......
此差异已折叠。
......@@ -400,8 +400,9 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int dead:1; /* Controller has died */
unsigned int working_RD:1; /* Suspended root hub doesn't
need to be polled */
unsigned int RD_enable:1; /* Suspended root hub with
Resume-Detect interrupts
enabled */
unsigned int is_initialized:1; /* Data structure is usable */
unsigned int fsbr_is_on:1; /* FSBR is turned on */
unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -130,7 +130,7 @@ static int ch341_get_status(struct usb_device *dev)
return -ENOMEM;
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
if ( r < 0)
if (r < 0)
goto out;
/* Not having the datasheet for the CH341, we ignore the bytes returned
......
......@@ -133,6 +133,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
......
......@@ -40,6 +40,17 @@
/* AlphaMicro Components AMC-232USB01 device */
#define FTDI_AMC232_PID 0xFF00 /* Product Id */
/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
/* the VID is the standard ftdi vid (FTDI_VID) */
#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
#define FTDI_SCS_DEVICE_2_PID 0xD012
#define FTDI_SCS_DEVICE_3_PID 0xD013
#define FTDI_SCS_DEVICE_4_PID 0xD014
#define FTDI_SCS_DEVICE_5_PID 0xD015
#define FTDI_SCS_DEVICE_6_PID 0xD016
#define FTDI_SCS_DEVICE_7_PID 0xD017
/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
#define FTDI_ACTZWAVE_PID 0xF2D0
......
......@@ -1713,7 +1713,7 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
{
struct moschip_port *mos7840_port;
unsigned int mcr;
unsigned int status;
int status;
dbg("%s - port %d", __func__, port->number);
......@@ -1740,11 +1740,10 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
mos7840_port->shadowMCR = mcr;
status = 0;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
if (status < 0) {
dbg("setting MODEM_CONTROL_REGISTER Failed\n");
return -1;
return status;
}
return 0;
......
此差异已折叠。
......@@ -135,7 +135,7 @@ static int usu_probe(struct usb_interface *intf,
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册