mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-13 09:20:17 +00:00
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 ...
This commit is contained in:
commit
1be1d6b7f3
@ -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
|
||||
|
9
drivers/usb/c67x00/Makefile
Normal file
9
drivers/usb/c67x00/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# 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
|
243
drivers/usb/c67x00/c67x00-drv.c
Normal file
243
drivers/usb/c67x00/c67x00-drv.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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");
|
412
drivers/usb/c67x00/c67x00-hcd.c
Normal file
412
drivers/usb/c67x00/c67x00-hcd.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
133
drivers/usb/c67x00/c67x00-hcd.h
Normal file
133
drivers/usb/c67x00/c67x00-hcd.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 */
|
480
drivers/usb/c67x00/c67x00-ll-hpi.c
Normal file
480
drivers/usb/c67x00/c67x00-ll-hpi.c
Normal file
@ -0,0 +1,480 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
}
|
1170
drivers/usb/c67x00/c67x00-sched.c
Normal file
1170
drivers/usb/c67x00/c67x00-sched.c
Normal file
File diff suppressed because it is too large
Load Diff
294
drivers/usb/c67x00/c67x00.h
Normal file
294
drivers/usb/c67x00/c67x00.h
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
2404
drivers/usb/gadget/pxa27x_udc.c
Normal file
2404
drivers/usb/gadget/pxa27x_udc.c
Normal file
File diff suppressed because it is too large
Load Diff
487
drivers/usb/gadget/pxa27x_udc.h
Normal file
487
drivers/usb/gadget/pxa27x_udc.h
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* 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",
|
||||
|
@ -23,9 +23,7 @@
|
||||
/*
|
||||
* Gadget Zero only needs two bulk endpoints, and is an example of how you
|
||||
* can write a hardware-agnostic gadget driver running inside a USB device.
|
||||
*
|
||||
* Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
|
||||
* affect most of the driver.
|
||||
* Some hardware details are visible, but don't affect most of the driver.
|
||||
*
|
||||
* Use it with the Linux host/master side "usbtest" driver to get a basic
|
||||
* functional test of your device-side usb stack, or with "usb-skeleton".
|
||||
@ -37,6 +35,7 @@
|
||||
* buflen=N default N=4096, buffer size used
|
||||
* qlen=N default N=32, how many buffers in the loopback queue
|
||||
* loopdefault default false, list loopback config first
|
||||
* autoresume=N default N=0, seconds before triggering remote wakeup
|
||||
*
|
||||
* Many drivers will only have one configuration, letting them be much
|
||||
* simpler if they also don't support high speed operation (like this
|
||||
@ -62,13 +61,13 @@
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define DRIVER_VERSION "Lughnasadh, 2007"
|
||||
#define DRIVER_VERSION "Earth Day 2008"
|
||||
|
||||
static const char shortname [] = "zero";
|
||||
static const char longname [] = "Gadget Zero";
|
||||
static const char shortname[] = "zero";
|
||||
static const char longname[] = "Gadget Zero";
|
||||
|
||||
static const char source_sink [] = "source and sink data";
|
||||
static const char loopback [] = "loop input to output";
|
||||
static const char source_sink[] = "source and sink data";
|
||||
static const char loopback[] = "loop input to output";
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -120,16 +119,16 @@ static unsigned buflen = 4096;
|
||||
static unsigned qlen = 32;
|
||||
static unsigned pattern = 0;
|
||||
|
||||
module_param (buflen, uint, S_IRUGO);
|
||||
module_param (qlen, uint, S_IRUGO);
|
||||
module_param (pattern, uint, S_IRUGO|S_IWUSR);
|
||||
module_param(buflen, uint, S_IRUGO);
|
||||
module_param(qlen, uint, S_IRUGO);
|
||||
module_param(pattern, uint, S_IRUGO|S_IWUSR);
|
||||
|
||||
/*
|
||||
* if it's nonzero, autoresume says how many seconds to wait
|
||||
* before trying to wake up the host after suspend.
|
||||
*/
|
||||
static unsigned autoresume = 0;
|
||||
module_param (autoresume, uint, 0);
|
||||
module_param(autoresume, uint, 0);
|
||||
|
||||
/*
|
||||
* Normally the "loopback" configuration is second (index 1) so
|
||||
@ -138,8 +137,7 @@ module_param (autoresume, uint, 0);
|
||||
* Or controllers (like superh) that only support one config.
|
||||
*/
|
||||
static int loopdefault = 0;
|
||||
|
||||
module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -176,24 +174,22 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
#define CONFIG_SOURCE_SINK 3
|
||||
#define CONFIG_LOOPBACK 2
|
||||
|
||||
static struct usb_device_descriptor
|
||||
device_desc = {
|
||||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16 (0x0200),
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
|
||||
|
||||
.idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
|
||||
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
.iManufacturer = STRING_MANUFACTURER,
|
||||
.iProduct = STRING_PRODUCT,
|
||||
.iSerialNumber = STRING_SERIAL,
|
||||
.bNumConfigurations = 2,
|
||||
};
|
||||
|
||||
static struct usb_config_descriptor
|
||||
source_sink_config = {
|
||||
static struct usb_config_descriptor source_sink_config = {
|
||||
.bLength = sizeof source_sink_config,
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
|
||||
@ -205,8 +201,7 @@ source_sink_config = {
|
||||
.bMaxPower = 1, /* self-powered */
|
||||
};
|
||||
|
||||
static struct usb_config_descriptor
|
||||
loopback_config = {
|
||||
static struct usb_config_descriptor loopback_config = {
|
||||
.bLength = sizeof loopback_config,
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
|
||||
@ -218,8 +213,7 @@ loopback_config = {
|
||||
.bMaxPower = 1, /* self-powered */
|
||||
};
|
||||
|
||||
static struct usb_otg_descriptor
|
||||
otg_descriptor = {
|
||||
static struct usb_otg_descriptor otg_descriptor = {
|
||||
.bLength = sizeof otg_descriptor,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
@ -228,8 +222,7 @@ otg_descriptor = {
|
||||
|
||||
/* one interface in each configuration */
|
||||
|
||||
static const struct usb_interface_descriptor
|
||||
source_sink_intf = {
|
||||
static const struct usb_interface_descriptor source_sink_intf = {
|
||||
.bLength = sizeof source_sink_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -238,8 +231,7 @@ source_sink_intf = {
|
||||
.iInterface = STRING_SOURCE_SINK,
|
||||
};
|
||||
|
||||
static const struct usb_interface_descriptor
|
||||
loopback_intf = {
|
||||
static const struct usb_interface_descriptor loopback_intf = {
|
||||
.bLength = sizeof loopback_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -250,8 +242,7 @@ loopback_intf = {
|
||||
|
||||
/* two full speed bulk endpoints; their use is config-dependent */
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fs_source_desc = {
|
||||
static struct usb_endpoint_descriptor fs_source_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -259,8 +250,7 @@ fs_source_desc = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fs_sink_desc = {
|
||||
static struct usb_endpoint_descriptor fs_sink_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -268,7 +258,7 @@ fs_sink_desc = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header *fs_source_sink_function [] = {
|
||||
static const struct usb_descriptor_header *fs_source_sink_function[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
(struct usb_descriptor_header *) &source_sink_intf,
|
||||
(struct usb_descriptor_header *) &fs_sink_desc,
|
||||
@ -276,7 +266,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header *fs_loopback_function [] = {
|
||||
static const struct usb_descriptor_header *fs_loopback_function[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
(struct usb_descriptor_header *) &loopback_intf,
|
||||
(struct usb_descriptor_header *) &fs_sink_desc,
|
||||
@ -293,36 +283,33 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
|
||||
* for the config descriptor.
|
||||
*/
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
hs_source_desc = {
|
||||
static struct usb_endpoint_descriptor hs_source_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16 (512),
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
hs_sink_desc = {
|
||||
static struct usb_endpoint_descriptor hs_sink_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16 (512),
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor
|
||||
dev_qualifier = {
|
||||
static struct usb_qualifier_descriptor dev_qualifier = {
|
||||
.bLength = sizeof dev_qualifier,
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16 (0x0200),
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
|
||||
|
||||
.bNumConfigurations = 2,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header *hs_source_sink_function [] = {
|
||||
static const struct usb_descriptor_header *hs_source_sink_function[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
(struct usb_descriptor_header *) &source_sink_intf,
|
||||
(struct usb_descriptor_header *) &hs_source_desc,
|
||||
@ -330,7 +317,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header *hs_loopback_function [] = {
|
||||
static const struct usb_descriptor_header *hs_loopback_function[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
(struct usb_descriptor_header *) &loopback_intf,
|
||||
(struct usb_descriptor_header *) &hs_source_desc,
|
||||
@ -355,7 +342,7 @@ static char serial[] = "0123456789.0123456789.0123456789";
|
||||
|
||||
|
||||
/* static strings, in UTF-8 */
|
||||
static struct usb_string strings [] = {
|
||||
static struct usb_string strings[] = {
|
||||
{ STRING_MANUFACTURER, manufacturer, },
|
||||
{ STRING_PRODUCT, longname, },
|
||||
{ STRING_SERIAL, serial, },
|
||||
@ -364,7 +351,7 @@ static struct usb_string strings [] = {
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings stringtab = {
|
||||
static struct usb_gadget_strings stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings,
|
||||
};
|
||||
@ -387,8 +374,7 @@ static struct usb_gadget_strings stringtab = {
|
||||
* high bandwidth modes at high speed. (Maybe work like Intel's test
|
||||
* device?)
|
||||
*/
|
||||
static int
|
||||
config_buf (struct usb_gadget *gadget,
|
||||
static int config_buf(struct usb_gadget *gadget,
|
||||
u8 *buf, u8 type, unsigned index)
|
||||
{
|
||||
int is_source_sink;
|
||||
@ -419,7 +405,7 @@ config_buf (struct usb_gadget *gadget,
|
||||
if (!gadget_is_otg(gadget))
|
||||
function++;
|
||||
|
||||
len = usb_gadget_config_buf (is_source_sink
|
||||
len = usb_gadget_config_buf(is_source_sink
|
||||
? &source_sink_config
|
||||
: &loopback_config,
|
||||
buf, USB_BUFSIZ, function);
|
||||
@ -431,27 +417,26 @@ config_buf (struct usb_gadget *gadget,
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_request *
|
||||
alloc_ep_req (struct usb_ep *ep, unsigned length)
|
||||
static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request (ep, GFP_ATOMIC);
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
req->length = length;
|
||||
req->buf = kmalloc(length, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request (ep, req);
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
|
||||
static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request (ep, req);
|
||||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -472,7 +457,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
|
||||
/* optionally require specific source/sink data patterns */
|
||||
|
||||
static int
|
||||
check_read_data (
|
||||
check_read_data(
|
||||
struct zero_dev *dev,
|
||||
struct usb_ep *ep,
|
||||
struct usb_request *req
|
||||
@ -498,8 +483,8 @@ check_read_data (
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
|
||||
usb_ep_set_halt (ep);
|
||||
ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
|
||||
usb_ep_set_halt(ep);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@ -512,7 +497,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
|
||||
|
||||
switch (pattern) {
|
||||
case 0:
|
||||
memset (req->buf, 0, req->length);
|
||||
memset(req->buf, 0, req->length);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < req->length; i++)
|
||||
@ -525,7 +510,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
|
||||
* irq delay between end of one request and start of the next.
|
||||
* that prevents using hardware dma queues.
|
||||
*/
|
||||
static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct zero_dev *dev = ep->driver_data;
|
||||
int status = req->status;
|
||||
@ -534,8 +519,8 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
|
||||
case 0: /* normal completion? */
|
||||
if (ep == dev->out_ep) {
|
||||
check_read_data (dev, ep, req);
|
||||
memset (req->buf, 0x55, req->length);
|
||||
check_read_data(dev, ep, req);
|
||||
memset(req->buf, 0x55, req->length);
|
||||
} else
|
||||
reinit_write_data(ep, req);
|
||||
break;
|
||||
@ -544,11 +529,11 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
|
||||
VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
|
||||
req->actual, req->length);
|
||||
if (ep == dev->out_ep)
|
||||
check_read_data (dev, ep, req);
|
||||
free_ep_req (ep, req);
|
||||
check_read_data(dev, ep, req);
|
||||
free_ep_req(ep, req);
|
||||
return;
|
||||
|
||||
case -EOVERFLOW: /* buffer overrun on read means that
|
||||
@ -557,18 +542,18 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
*/
|
||||
default:
|
||||
#if 1
|
||||
DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
|
||||
DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
|
||||
status, req->actual, req->length);
|
||||
#endif
|
||||
case -EREMOTEIO: /* short read */
|
||||
break;
|
||||
}
|
||||
|
||||
status = usb_ep_queue (ep, req, GFP_ATOMIC);
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status) {
|
||||
ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
|
||||
ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
|
||||
ep->name, req->length, status);
|
||||
usb_ep_set_halt (ep);
|
||||
usb_ep_set_halt(ep);
|
||||
/* FIXME recover later ... somehow */
|
||||
}
|
||||
}
|
||||
@ -578,24 +563,24 @@ static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
|
||||
struct usb_request *req;
|
||||
int status;
|
||||
|
||||
req = alloc_ep_req (ep, buflen);
|
||||
req = alloc_ep_req(ep, buflen);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
memset (req->buf, 0, req->length);
|
||||
memset(req->buf, 0, req->length);
|
||||
req->complete = source_sink_complete;
|
||||
|
||||
if (strcmp (ep->name, EP_IN_NAME) == 0)
|
||||
if (strcmp(ep->name, EP_IN_NAME) == 0)
|
||||
reinit_write_data(ep, req);
|
||||
else
|
||||
memset (req->buf, 0x55, req->length);
|
||||
memset(req->buf, 0x55, req->length);
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status) {
|
||||
struct zero_dev *dev = ep->driver_data;
|
||||
|
||||
ERROR (dev, "start %s --> %d\n", ep->name, status);
|
||||
free_ep_req (ep, req);
|
||||
ERROR(dev, "start %s --> %d\n", ep->name, status);
|
||||
free_ep_req(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
|
||||
@ -608,34 +593,34 @@ static int set_source_sink_config(struct zero_dev *dev)
|
||||
struct usb_ep *ep;
|
||||
struct usb_gadget *gadget = dev->gadget;
|
||||
|
||||
gadget_for_each_ep (ep, gadget) {
|
||||
gadget_for_each_ep(ep, gadget) {
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
|
||||
/* one endpoint writes (sources) zeroes in (to the host) */
|
||||
if (strcmp (ep->name, EP_IN_NAME) == 0) {
|
||||
d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
|
||||
result = usb_ep_enable (ep, d);
|
||||
if (strcmp(ep->name, EP_IN_NAME) == 0) {
|
||||
d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
|
||||
result = usb_ep_enable(ep, d);
|
||||
if (result == 0) {
|
||||
ep->driver_data = dev;
|
||||
if (source_sink_start_ep(ep) != NULL) {
|
||||
dev->in_ep = ep;
|
||||
continue;
|
||||
}
|
||||
usb_ep_disable (ep);
|
||||
usb_ep_disable(ep);
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
/* one endpoint reads (sinks) anything out (from the host) */
|
||||
} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
|
||||
d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
|
||||
result = usb_ep_enable (ep, d);
|
||||
} else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
|
||||
d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
|
||||
result = usb_ep_enable(ep, d);
|
||||
if (result == 0) {
|
||||
ep->driver_data = dev;
|
||||
if (source_sink_start_ep(ep) != NULL) {
|
||||
dev->out_ep = ep;
|
||||
continue;
|
||||
}
|
||||
usb_ep_disable (ep);
|
||||
usb_ep_disable(ep);
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
@ -644,11 +629,11 @@ static int set_source_sink_config(struct zero_dev *dev)
|
||||
continue;
|
||||
|
||||
/* stop on error */
|
||||
ERROR (dev, "can't start %s, result %d\n", ep->name, result);
|
||||
ERROR(dev, "can't start %s, result %d\n", ep->name, result);
|
||||
break;
|
||||
}
|
||||
if (result == 0)
|
||||
DBG (dev, "buflen %d\n", buflen);
|
||||
DBG(dev, "buflen %d\n", buflen);
|
||||
|
||||
/* caller is responsible for cleanup on error */
|
||||
return result;
|
||||
@ -656,7 +641,7 @@ static int set_source_sink_config(struct zero_dev *dev)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct zero_dev *dev = ep->driver_data;
|
||||
int status = req->status;
|
||||
@ -668,19 +653,19 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
/* loop this OUT packet back IN to the host */
|
||||
req->zero = (req->actual < req->length);
|
||||
req->length = req->actual;
|
||||
status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
|
||||
status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
|
||||
if (status == 0)
|
||||
return;
|
||||
|
||||
/* "should never get here" */
|
||||
ERROR (dev, "can't loop %s to %s: %d\n",
|
||||
ERROR(dev, "can't loop %s to %s: %d\n",
|
||||
ep->name, dev->in_ep->name,
|
||||
status);
|
||||
}
|
||||
|
||||
/* queue the buffer for some later OUT packet */
|
||||
req->length = buflen;
|
||||
status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
|
||||
status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
|
||||
if (status == 0)
|
||||
return;
|
||||
|
||||
@ -688,7 +673,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
|
||||
ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
|
||||
status, req->actual, req->length);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
@ -700,7 +685,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
free_ep_req (ep, req);
|
||||
free_ep_req(ep, req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -711,13 +696,13 @@ static int set_loopback_config(struct zero_dev *dev)
|
||||
struct usb_ep *ep;
|
||||
struct usb_gadget *gadget = dev->gadget;
|
||||
|
||||
gadget_for_each_ep (ep, gadget) {
|
||||
gadget_for_each_ep(ep, gadget) {
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
|
||||
/* one endpoint writes data back IN to the host */
|
||||
if (strcmp (ep->name, EP_IN_NAME) == 0) {
|
||||
d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
|
||||
result = usb_ep_enable (ep, d);
|
||||
if (strcmp(ep->name, EP_IN_NAME) == 0) {
|
||||
d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
|
||||
result = usb_ep_enable(ep, d);
|
||||
if (result == 0) {
|
||||
ep->driver_data = dev;
|
||||
dev->in_ep = ep;
|
||||
@ -725,9 +710,9 @@ static int set_loopback_config(struct zero_dev *dev)
|
||||
}
|
||||
|
||||
/* one endpoint just reads OUT packets */
|
||||
} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
|
||||
d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
|
||||
result = usb_ep_enable (ep, d);
|
||||
} else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
|
||||
d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
|
||||
result = usb_ep_enable(ep, d);
|
||||
if (result == 0) {
|
||||
ep->driver_data = dev;
|
||||
dev->out_ep = ep;
|
||||
@ -739,7 +724,7 @@ static int set_loopback_config(struct zero_dev *dev)
|
||||
continue;
|
||||
|
||||
/* stop on error */
|
||||
ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
|
||||
ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -753,19 +738,19 @@ static int set_loopback_config(struct zero_dev *dev)
|
||||
|
||||
ep = dev->out_ep;
|
||||
for (i = 0; i < qlen && result == 0; i++) {
|
||||
req = alloc_ep_req (ep, buflen);
|
||||
req = alloc_ep_req(ep, buflen);
|
||||
if (req) {
|
||||
req->complete = loopback_complete;
|
||||
result = usb_ep_queue (ep, req, GFP_ATOMIC);
|
||||
result = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (result)
|
||||
DBG (dev, "%s queue req --> %d\n",
|
||||
DBG(dev, "%s queue req --> %d\n",
|
||||
ep->name, result);
|
||||
} else
|
||||
result = -ENOMEM;
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
|
||||
DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
|
||||
|
||||
/* caller is responsible for cleanup on error */
|
||||
return result;
|
||||
@ -773,26 +758,26 @@ static int set_loopback_config(struct zero_dev *dev)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void zero_reset_config (struct zero_dev *dev)
|
||||
static void zero_reset_config(struct zero_dev *dev)
|
||||
{
|
||||
if (dev->config == 0)
|
||||
return;
|
||||
|
||||
DBG (dev, "reset config\n");
|
||||
DBG(dev, "reset config\n");
|
||||
|
||||
/* just disable endpoints, forcing completion of pending i/o.
|
||||
* all our completion handlers free their requests in this case.
|
||||
*/
|
||||
if (dev->in_ep) {
|
||||
usb_ep_disable (dev->in_ep);
|
||||
usb_ep_disable(dev->in_ep);
|
||||
dev->in_ep = NULL;
|
||||
}
|
||||
if (dev->out_ep) {
|
||||
usb_ep_disable (dev->out_ep);
|
||||
usb_ep_disable(dev->out_ep);
|
||||
dev->out_ep = NULL;
|
||||
}
|
||||
dev->config = 0;
|
||||
del_timer (&dev->resume);
|
||||
del_timer(&dev->resume);
|
||||
}
|
||||
|
||||
/* change our operational config. this code must agree with the code
|
||||
@ -813,12 +798,12 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
|
||||
if (number == dev->config)
|
||||
return 0;
|
||||
|
||||
if (gadget_is_sa1100 (gadget) && dev->config) {
|
||||
if (gadget_is_sa1100(gadget) && dev->config) {
|
||||
/* tx fifo is full, but we can't clear it...*/
|
||||
ERROR(dev, "can't change configurations\n");
|
||||
return -ESPIPE;
|
||||
}
|
||||
zero_reset_config (dev);
|
||||
zero_reset_config(dev);
|
||||
|
||||
switch (number) {
|
||||
case CONFIG_SOURCE_SINK:
|
||||
@ -837,7 +822,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
|
||||
if (!result && (!dev->in_ep || !dev->out_ep))
|
||||
result = -ENODEV;
|
||||
if (result)
|
||||
zero_reset_config (dev);
|
||||
zero_reset_config(dev);
|
||||
else {
|
||||
char *speed;
|
||||
|
||||
@ -849,7 +834,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
|
||||
}
|
||||
|
||||
dev->config = number;
|
||||
INFO (dev, "%s speed config #%d: %s\n", speed, number,
|
||||
INFO(dev, "%s speed config #%d: %s\n", speed, number,
|
||||
(number == CONFIG_SOURCE_SINK)
|
||||
? source_sink : loopback);
|
||||
}
|
||||
@ -858,10 +843,10 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
if (req->status || req->actual != req->length)
|
||||
DBG ((struct zero_dev *) ep->driver_data,
|
||||
DBG((struct zero_dev *) ep->driver_data,
|
||||
"setup complete --> %d, %d/%d\n",
|
||||
req->status, req->actual, req->length);
|
||||
}
|
||||
@ -874,9 +859,9 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
|
||||
* the work is in config-specific setup.
|
||||
*/
|
||||
static int
|
||||
zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
struct zero_dev *dev = get_gadget_data(gadget);
|
||||
struct usb_request *req = dev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
@ -895,14 +880,14 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
switch (w_value >> 8) {
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
value = min (w_length, (u16) sizeof device_desc);
|
||||
memcpy (req->buf, &device_desc, value);
|
||||
value = min(w_length, (u16) sizeof device_desc);
|
||||
memcpy(req->buf, &device_desc, value);
|
||||
break;
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
if (!gadget_is_dualspeed(gadget))
|
||||
break;
|
||||
value = min (w_length, (u16) sizeof dev_qualifier);
|
||||
memcpy (req->buf, &dev_qualifier, value);
|
||||
value = min(w_length, (u16) sizeof dev_qualifier);
|
||||
memcpy(req->buf, &dev_qualifier, value);
|
||||
break;
|
||||
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
@ -910,11 +895,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
break;
|
||||
// FALLTHROUGH
|
||||
case USB_DT_CONFIG:
|
||||
value = config_buf (gadget, req->buf,
|
||||
value = config_buf(gadget, req->buf,
|
||||
w_value >> 8,
|
||||
w_value & 0xff);
|
||||
if (value >= 0)
|
||||
value = min (w_length, (u16) value);
|
||||
value = min(w_length, (u16) value);
|
||||
break;
|
||||
|
||||
case USB_DT_STRING:
|
||||
@ -923,10 +908,10 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
* add string tables for other languages, using
|
||||
* any UTF-8 characters
|
||||
*/
|
||||
value = usb_gadget_get_string (&stringtab,
|
||||
value = usb_gadget_get_string(&stringtab,
|
||||
w_value & 0xff, req->buf);
|
||||
if (value >= 0)
|
||||
value = min (w_length, (u16) value);
|
||||
value = min(w_length, (u16) value);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -936,20 +921,20 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
if (ctrl->bRequestType != 0)
|
||||
goto unknown;
|
||||
if (gadget->a_hnp_support)
|
||||
DBG (dev, "HNP available\n");
|
||||
DBG(dev, "HNP available\n");
|
||||
else if (gadget->a_alt_hnp_support)
|
||||
DBG (dev, "HNP needs a different root port\n");
|
||||
DBG(dev, "HNP needs a different root port\n");
|
||||
else
|
||||
VDBG (dev, "HNP inactive\n");
|
||||
spin_lock (&dev->lock);
|
||||
VDBG(dev, "HNP inactive\n");
|
||||
spin_lock(&dev->lock);
|
||||
value = zero_set_config(dev, w_value);
|
||||
spin_unlock (&dev->lock);
|
||||
spin_unlock(&dev->lock);
|
||||
break;
|
||||
case USB_REQ_GET_CONFIGURATION:
|
||||
if (ctrl->bRequestType != USB_DIR_IN)
|
||||
goto unknown;
|
||||
*(u8 *)req->buf = dev->config;
|
||||
value = min (w_length, (u16) 1);
|
||||
value = min(w_length, (u16) 1);
|
||||
break;
|
||||
|
||||
/* until we add altsetting support, or other interfaces,
|
||||
@ -959,7 +944,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
|
||||
goto unknown;
|
||||
spin_lock (&dev->lock);
|
||||
spin_lock(&dev->lock);
|
||||
if (dev->config && w_index == 0 && w_value == 0) {
|
||||
u8 config = dev->config;
|
||||
|
||||
@ -970,11 +955,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
* if we had more than one interface we couldn't
|
||||
* use this "reset the config" shortcut.
|
||||
*/
|
||||
zero_reset_config (dev);
|
||||
zero_reset_config(dev);
|
||||
zero_set_config(dev, config);
|
||||
value = 0;
|
||||
}
|
||||
spin_unlock (&dev->lock);
|
||||
spin_unlock(&dev->lock);
|
||||
break;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
|
||||
@ -986,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
break;
|
||||
}
|
||||
*(u8 *)req->buf = 0;
|
||||
value = min (w_length, (u16) 1);
|
||||
value = min(w_length, (u16) 1);
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1018,7 +1003,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
|
||||
default:
|
||||
unknown:
|
||||
VDBG (dev,
|
||||
VDBG(dev,
|
||||
"unknown control req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
@ -1028,11 +1013,11 @@ unknown:
|
||||
if (value >= 0) {
|
||||
req->length = value;
|
||||
req->zero = value < w_length;
|
||||
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
|
||||
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0) {
|
||||
DBG (dev, "ep_queue --> %d\n", value);
|
||||
DBG(dev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
zero_setup_complete (gadget->ep0, req);
|
||||
zero_setup_complete(gadget->ep0, req);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1040,28 +1025,26 @@ unknown:
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
zero_disconnect (struct usb_gadget *gadget)
|
||||
static void zero_disconnect(struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
struct zero_dev *dev = get_gadget_data(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave (&dev->lock, flags);
|
||||
zero_reset_config (dev);
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
zero_reset_config(dev);
|
||||
|
||||
/* a more significant application might have some non-usb
|
||||
* activities to quiesce here, saving resources like power
|
||||
* or pushing the notification up a network stack.
|
||||
*/
|
||||
spin_unlock_irqrestore (&dev->lock, flags);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
/* next we may get setup() calls to enumerate new connections;
|
||||
* or an unbind() during shutdown (including removing module).
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
zero_autoresume (unsigned long _dev)
|
||||
static void zero_autoresume(unsigned long _dev)
|
||||
{
|
||||
struct zero_dev *dev = (struct zero_dev *) _dev;
|
||||
int status;
|
||||
@ -1070,32 +1053,30 @@ zero_autoresume (unsigned long _dev)
|
||||
* more significant than just a timer firing...
|
||||
*/
|
||||
if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
|
||||
status = usb_gadget_wakeup (dev->gadget);
|
||||
DBG (dev, "wakeup --> %d\n", status);
|
||||
status = usb_gadget_wakeup(dev->gadget);
|
||||
DBG(dev, "wakeup --> %d\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void /* __init_or_exit */
|
||||
zero_unbind (struct usb_gadget *gadget)
|
||||
static void zero_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
struct zero_dev *dev = get_gadget_data(gadget);
|
||||
|
||||
DBG (dev, "unbind\n");
|
||||
DBG(dev, "unbind\n");
|
||||
|
||||
/* we've already been disconnected ... no i/o is active */
|
||||
if (dev->req) {
|
||||
dev->req->length = USB_BUFSIZ;
|
||||
free_ep_req (gadget->ep0, dev->req);
|
||||
free_ep_req(gadget->ep0, dev->req);
|
||||
}
|
||||
del_timer_sync (&dev->resume);
|
||||
kfree (dev);
|
||||
set_gadget_data (gadget, NULL);
|
||||
del_timer_sync(&dev->resume);
|
||||
kfree(dev);
|
||||
set_gadget_data(gadget, NULL);
|
||||
}
|
||||
|
||||
static int __init
|
||||
zero_bind (struct usb_gadget *gadget)
|
||||
static int __init zero_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev;
|
||||
struct usb_ep *ep;
|
||||
@ -1111,8 +1092,8 @@ zero_bind (struct usb_gadget *gadget)
|
||||
* autoconfigure on any sane usb controller driver,
|
||||
* but there may also be important quirks to address.
|
||||
*/
|
||||
usb_ep_autoconfig_reset (gadget);
|
||||
ep = usb_ep_autoconfig (gadget, &fs_source_desc);
|
||||
usb_ep_autoconfig_reset(gadget);
|
||||
ep = usb_ep_autoconfig(gadget, &fs_source_desc);
|
||||
if (!ep) {
|
||||
autoconf_fail:
|
||||
pr_err("%s: can't autoconfigure on %s\n",
|
||||
@ -1122,15 +1103,15 @@ autoconf_fail:
|
||||
EP_IN_NAME = ep->name;
|
||||
ep->driver_data = ep; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
|
||||
ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
|
||||
if (!ep)
|
||||
goto autoconf_fail;
|
||||
EP_OUT_NAME = ep->name;
|
||||
ep->driver_data = ep; /* claim */
|
||||
|
||||
gcnum = usb_gadget_controller_number (gadget);
|
||||
gcnum = usb_gadget_controller_number(gadget);
|
||||
if (gcnum >= 0)
|
||||
device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
|
||||
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
|
||||
else {
|
||||
/* gadget zero is so simple (for now, no altsettings) that
|
||||
* it SHOULD NOT have problems with bulk-capable hardware.
|
||||
@ -1141,7 +1122,7 @@ autoconf_fail:
|
||||
*/
|
||||
pr_warning("%s: controller '%s' not recognized\n",
|
||||
shortname, gadget->name);
|
||||
device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
|
||||
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
|
||||
}
|
||||
|
||||
|
||||
@ -1149,12 +1130,16 @@ autoconf_fail:
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
spin_lock_init (&dev->lock);
|
||||
spin_lock_init(&dev->lock);
|
||||
dev->gadget = gadget;
|
||||
set_gadget_data (gadget, dev);
|
||||
set_gadget_data(gadget, dev);
|
||||
|
||||
init_timer(&dev->resume);
|
||||
dev->resume.function = zero_autoresume;
|
||||
dev->resume.data = (unsigned long) dev;
|
||||
|
||||
/* preallocate control response and buffer */
|
||||
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
|
||||
dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
|
||||
if (!dev->req)
|
||||
goto enomem;
|
||||
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
|
||||
@ -1182,11 +1167,8 @@ autoconf_fail:
|
||||
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
usb_gadget_set_selfpowered (gadget);
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
init_timer (&dev->resume);
|
||||
dev->resume.function = zero_autoresume;
|
||||
dev->resume.data = (unsigned long) dev;
|
||||
if (autoresume) {
|
||||
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
@ -1194,45 +1176,43 @@ autoconf_fail:
|
||||
|
||||
gadget->ep0->driver_data = dev;
|
||||
|
||||
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
|
||||
INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
|
||||
INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
|
||||
INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
|
||||
EP_OUT_NAME, EP_IN_NAME);
|
||||
|
||||
snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
|
||||
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
gadget->name);
|
||||
|
||||
return 0;
|
||||
|
||||
enomem:
|
||||
zero_unbind (gadget);
|
||||
zero_unbind(gadget);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
zero_suspend (struct usb_gadget *gadget)
|
||||
static void zero_suspend(struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
struct zero_dev *dev = get_gadget_data(gadget);
|
||||
|
||||
if (gadget->speed == USB_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
if (autoresume) {
|
||||
mod_timer (&dev->resume, jiffies + (HZ * autoresume));
|
||||
DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
mod_timer(&dev->resume, jiffies + (HZ * autoresume));
|
||||
DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
} else
|
||||
DBG (dev, "suspend\n");
|
||||
DBG(dev, "suspend\n");
|
||||
}
|
||||
|
||||
static void
|
||||
zero_resume (struct usb_gadget *gadget)
|
||||
static void zero_resume(struct usb_gadget *gadget)
|
||||
{
|
||||
struct zero_dev *dev = get_gadget_data (gadget);
|
||||
struct zero_dev *dev = get_gadget_data(gadget);
|
||||
|
||||
DBG (dev, "resume\n");
|
||||
del_timer (&dev->resume);
|
||||
DBG(dev, "resume\n");
|
||||
del_timer(&dev->resume);
|
||||
}
|
||||
|
||||
|
||||
@ -1264,15 +1244,15 @@ MODULE_AUTHOR("David Brownell");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int __init init (void)
|
||||
static int __init init(void)
|
||||
{
|
||||
return usb_gadget_register_driver (&zero_driver);
|
||||
return usb_gadget_register_driver(&zero_driver);
|
||||
}
|
||||
module_init (init);
|
||||
module_init(init);
|
||||
|
||||
static void __exit cleanup (void)
|
||||
static void __exit cleanup(void)
|
||||
{
|
||||
usb_gadget_unregister_driver (&zero_driver);
|
||||
usb_gadget_unregister_driver(&zero_driver);
|
||||
}
|
||||
module_exit (cleanup);
|
||||
module_exit(cleanup);
|
||||
|
||||
|
@ -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
|
||||
|
2231
drivers/usb/host/isp1760-hcd.c
Normal file
2231
drivers/usb/host/isp1760-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
206
drivers/usb/host/isp1760-hcd.h
Normal file
206
drivers/usb/host/isp1760-hcd.h
Normal file
@ -0,0 +1,206 @@
|
||||
#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
|
298
drivers/usb/host/isp1760-if.c
Normal file
298
drivers/usb/host/isp1760-if.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Glue code for the ISP1760 driver and bus
|
||||
* Currently there is support for
|
||||
* - OpenFirmware
|
||||
* - PCI
|
||||
*
|
||||
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "../core/hcd.h"
|
||||
#include "isp1760-hcd.h"
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_OF
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_PCI
|
||||
#include <linux/pci.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_OF
|
||||
static int of_isp1760_probe(struct of_device *dev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct device_node *dp = dev->node;
|
||||
struct resource *res;
|
||||
struct resource memory;
|
||||
struct of_irq oirq;
|
||||
int virq;
|
||||
u64 res_len;
|
||||
int ret;
|
||||
|
||||
ret = of_address_to_resource(dp, 0, &memory);
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
res = request_mem_region(memory.start, memory.end - memory.start + 1,
|
||||
dev->dev.bus_id);
|
||||
if (!res)
|
||||
return -EBUSY;
|
||||
|
||||
res_len = memory.end - memory.start + 1;
|
||||
|
||||
if (of_irq_map_one(dp, 0, &oirq)) {
|
||||
ret = -ENODEV;
|
||||
goto release_reg;
|
||||
}
|
||||
|
||||
virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
|
||||
oirq.size);
|
||||
|
||||
hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret = PTR_ERR(hcd);
|
||||
goto release_reg;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&dev->dev, hcd);
|
||||
return ret;
|
||||
|
||||
release_reg:
|
||||
release_mem_region(memory.start, memory.end - memory.start + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int of_isp1760_remove(struct of_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
|
||||
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id of_isp1760_match[] = {
|
||||
{
|
||||
.compatible = "nxp,usb-isp1760",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_isp1760_match);
|
||||
|
||||
static struct of_platform_driver isp1760_of_driver = {
|
||||
.name = "nxp-isp1760",
|
||||
.match_table = of_isp1760_match,
|
||||
.probe = of_isp1760_probe,
|
||||
.remove = of_isp1760_remove,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_PCI
|
||||
static u32 nxp_pci_io_base;
|
||||
static u32 iolength;
|
||||
static u32 pci_mem_phy0;
|
||||
static u32 length;
|
||||
static u8 *chip_addr;
|
||||
static u8 *iobase;
|
||||
|
||||
static int __devinit isp1761_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
u8 latency, limit;
|
||||
__u32 reg_data;
|
||||
int retry_count;
|
||||
int length;
|
||||
int status = 1;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
if (pci_enable_device(dev) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dev->irq)
|
||||
return -ENODEV;
|
||||
|
||||
/* Grab the PLX PCI mem maped port start address we need */
|
||||
nxp_pci_io_base = pci_resource_start(dev, 0);
|
||||
iolength = pci_resource_len(dev, 0);
|
||||
|
||||
if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
|
||||
printk(KERN_ERR "request region #1\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
iobase = ioremap_nocache(nxp_pci_io_base, iolength);
|
||||
if (!iobase) {
|
||||
printk(KERN_ERR "ioremap #1\n");
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
|
||||
pci_mem_phy0 = pci_resource_start(dev, 3);
|
||||
length = pci_resource_len(dev, 3);
|
||||
|
||||
if (length < 0xffff) {
|
||||
printk(KERN_ERR "memory length for this resource is less than "
|
||||
"required\n");
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
iounmap(iobase);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
|
||||
printk(KERN_ERR "host controller already in use\n");
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
iounmap(iobase);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* bad pci latencies can contribute to overruns */
|
||||
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
|
||||
if (latency) {
|
||||
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
|
||||
if (limit && limit < latency)
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
|
||||
}
|
||||
|
||||
/* Try to check whether we can access Scratch Register of
|
||||
* Host Controller or not. The initial PCI access is retried until
|
||||
* local init for the PCI bridge is completed
|
||||
*/
|
||||
retry_count = 20;
|
||||
reg_data = 0;
|
||||
while ((reg_data != 0xFACE) && retry_count) {
|
||||
/*by default host is in 16bit mode, so
|
||||
* io operations at this stage must be 16 bit
|
||||
* */
|
||||
writel(0xface, chip_addr + HC_SCRATCH_REG);
|
||||
udelay(100);
|
||||
reg_data = readl(chip_addr + HC_SCRATCH_REG);
|
||||
retry_count--;
|
||||
}
|
||||
|
||||
/* Host Controller presence is detected by writing to scratch register
|
||||
* and reading back and checking the contents are same or not
|
||||
*/
|
||||
if (reg_data != 0xFACE) {
|
||||
err("scratch register mismatch %x", reg_data);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
status = readl(iobase + 0x68);
|
||||
status |= 0x900;
|
||||
writel(status, iobase + 0x68);
|
||||
|
||||
dev->dev.dma_mask = NULL;
|
||||
hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
|
||||
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
|
||||
pci_set_drvdata(dev, hcd);
|
||||
if (!hcd)
|
||||
return 0;
|
||||
clean:
|
||||
status = -ENODEV;
|
||||
iounmap(iobase);
|
||||
release_mem_region(pci_mem_phy0, length);
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
return status;
|
||||
}
|
||||
static void isp1761_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = pci_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
pci_disable_device(dev);
|
||||
|
||||
iounmap(iobase);
|
||||
iounmap(chip_addr);
|
||||
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
release_mem_region(pci_mem_phy0, length);
|
||||
}
|
||||
|
||||
static void isp1761_pci_shutdown(struct pci_dev *dev)
|
||||
{
|
||||
printk(KERN_ERR "ips1761_pci_shutdown\n");
|
||||
}
|
||||
|
||||
static const struct pci_device_id isp1760_plx [] = { {
|
||||
/* handle any USB 2.0 EHCI controller */
|
||||
PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
|
||||
.driver_data = 0,
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, isp1760_plx);
|
||||
|
||||
static struct pci_driver isp1761_pci_driver = {
|
||||
.name = "isp1760",
|
||||
.id_table = isp1760_plx,
|
||||
.probe = isp1761_pci_probe,
|
||||
.remove = isp1761_pci_remove,
|
||||
.shutdown = isp1761_pci_shutdown,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init isp1760_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
init_kmem_once();
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_OF
|
||||
ret = of_register_platform_driver(&isp1760_of_driver);
|
||||
if (ret) {
|
||||
deinit_kmem_cache();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_USB_ISP1760_PCI
|
||||
ret = pci_register_driver(&isp1761_pci_driver);
|
||||
if (ret)
|
||||
goto unreg_of;
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_USB_ISP1760_PCI
|
||||
unreg_of:
|
||||
#endif
|
||||
#ifdef CONFIG_USB_ISP1760_OF
|
||||
of_unregister_platform_driver(&isp1760_of_driver);
|
||||
#endif
|
||||
deinit_kmem_cache();
|
||||
return ret;
|
||||
}
|
||||
module_init(isp1760_init);
|
||||
|
||||
static void __exit isp1760_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_USB_ISP1760_OF
|
||||
of_unregister_platform_driver(&isp1760_of_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_USB_ISP1760_PCI
|
||||
pci_unregister_driver(&isp1761_pci_driver);
|
||||
#endif
|
||||
deinit_kmem_cache();
|
||||
}
|
||||
module_exit(isp1760_exit);
|
@ -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);
|
||||
|
@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
|
||||
static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
const char *sys_info;
|
||||
@ -261,27 +261,60 @@ __releases(uhci->lock)
|
||||
__acquires(uhci->lock)
|
||||
{
|
||||
int auto_stop;
|
||||
int int_enable, egsm_enable;
|
||||
int int_enable, egsm_enable, wakeup_enable;
|
||||
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
|
||||
|
||||
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
|
||||
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
|
||||
(auto_stop ? " (auto-stop)" : ""));
|
||||
|
||||
/* Enable resume-detect interrupts if they work.
|
||||
* Then enter Global Suspend mode if _it_ works, still configured.
|
||||
/* Start off by assuming Resume-Detect interrupts and EGSM work
|
||||
* and that remote wakeups should be enabled.
|
||||
*/
|
||||
egsm_enable = USBCMD_EGSM;
|
||||
uhci->working_RD = 1;
|
||||
uhci->RD_enable = 1;
|
||||
int_enable = USBINTR_RESUME;
|
||||
if (remote_wakeup_is_broken(uhci))
|
||||
egsm_enable = 0;
|
||||
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
|
||||
wakeup_enable = 1;
|
||||
|
||||
/* In auto-stop mode wakeups must always be detected, but
|
||||
* Resume-Detect interrupts may be prohibited. (In the absence
|
||||
* of CONFIG_PM, they are always disallowed.)
|
||||
*/
|
||||
if (auto_stop) {
|
||||
if (!device_may_wakeup(&rhdev->dev))
|
||||
int_enable = 0;
|
||||
|
||||
/* In bus-suspend mode wakeups may be disabled, but if they are
|
||||
* allowed then so are Resume-Detect interrupts.
|
||||
*/
|
||||
} else {
|
||||
#ifdef CONFIG_PM
|
||||
(!auto_stop && !rhdev->do_remote_wakeup) ||
|
||||
if (!rhdev->do_remote_wakeup)
|
||||
wakeup_enable = 0;
|
||||
#endif
|
||||
(auto_stop && !device_may_wakeup(&rhdev->dev)))
|
||||
uhci->working_RD = int_enable = 0;
|
||||
}
|
||||
|
||||
/* EGSM causes the root hub to echo a 'K' signal (resume) out any
|
||||
* port which requests a remote wakeup. According to the USB spec,
|
||||
* every hub is supposed to do this. But if we are ignoring
|
||||
* remote-wakeup requests anyway then there's no point to it.
|
||||
* We also shouldn't enable EGSM if it's broken.
|
||||
*/
|
||||
if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
|
||||
egsm_enable = 0;
|
||||
|
||||
/* If we're ignoring wakeup events then there's no reason to
|
||||
* enable Resume-Detect interrupts. We also shouldn't enable
|
||||
* them if they are broken or disallowed.
|
||||
*
|
||||
* This logic may lead us to enabling RD but not EGSM. The UHCI
|
||||
* spec foolishly says that RD works only when EGSM is on, but
|
||||
* there's no harm in enabling it anyway -- perhaps some chips
|
||||
* will implement it!
|
||||
*/
|
||||
if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
|
||||
!int_enable)
|
||||
uhci->RD_enable = int_enable = 0;
|
||||
|
||||
outw(int_enable, uhci->io_addr + USBINTR);
|
||||
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
|
||||
@ -308,7 +341,11 @@ __acquires(uhci->lock)
|
||||
|
||||
uhci->rh_state = new_state;
|
||||
uhci->is_stopped = UHCI_IS_STOPPED;
|
||||
uhci_to_hcd(uhci)->poll_rh = !int_enable;
|
||||
|
||||
/* If interrupts don't work and remote wakeup is enabled then
|
||||
* the suspended root hub needs to be polled.
|
||||
*/
|
||||
uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
|
||||
|
||||
uhci_scan_schedule(uhci);
|
||||
uhci_fsbr_off(uhci);
|
||||
@ -344,9 +381,12 @@ __acquires(uhci->lock)
|
||||
* for 20 ms.
|
||||
*/
|
||||
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
|
||||
unsigned egsm;
|
||||
|
||||
/* Keep EGSM on if it was set before */
|
||||
egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
|
||||
uhci->rh_state = UHCI_RH_RESUMING;
|
||||
outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
|
||||
uhci->io_addr + USBCMD);
|
||||
outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
msleep(20);
|
||||
spin_lock_irq(&uhci->lock);
|
||||
@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
|
||||
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
|
||||
if (!uhci->working_RD) {
|
||||
/* Suspended root hub needs to be polled */
|
||||
/* If interrupts don't work and remote wakeup is enabled then
|
||||
* the suspended root hub needs to be polled.
|
||||
*/
|
||||
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
|
||||
hcd->poll_rh = 1;
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
}
|
||||
|
@ -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? */
|
||||
|
@ -148,7 +148,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
|
||||
|
||||
/* Structure to hold all of our device specific stuff */
|
||||
struct ld_usb {
|
||||
struct semaphore sem; /* locks this structure */
|
||||
struct mutex mutex; /* locks this structure */
|
||||
struct usb_interface* intf; /* save off the usb interface pointer */
|
||||
|
||||
int open_count; /* number of times this port has been opened */
|
||||
@ -319,7 +319,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
|
||||
return -ENODEV;
|
||||
|
||||
/* lock this device */
|
||||
if (down_interruptible(&dev->sem))
|
||||
if (mutex_lock_interruptible(&dev->mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* allow opening only once */
|
||||
@ -358,7 +358,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
|
||||
file->private_data = dev;
|
||||
|
||||
unlock_exit:
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -378,7 +378,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (down_interruptible(&dev->sem)) {
|
||||
if (mutex_lock_interruptible(&dev->mutex)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
}
|
||||
@ -389,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
|
||||
}
|
||||
if (dev->intf == NULL) {
|
||||
/* the device was unplugged before the file was released */
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
/* unlock here as ld_usb_delete frees dev */
|
||||
ld_usb_delete(dev);
|
||||
goto exit;
|
||||
@ -402,7 +402,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
|
||||
dev->open_count = 0;
|
||||
|
||||
unlock_exit:
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
@ -448,7 +448,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
|
||||
goto exit;
|
||||
|
||||
/* lock this object */
|
||||
if (down_interruptible(&dev->sem)) {
|
||||
if (mutex_lock_interruptible(&dev->mutex)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
}
|
||||
@ -505,7 +505,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
|
||||
|
||||
unlock_exit:
|
||||
/* unlock the device */
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
@ -528,7 +528,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
|
||||
goto exit;
|
||||
|
||||
/* lock this object */
|
||||
if (down_interruptible(&dev->sem)) {
|
||||
if (mutex_lock_interruptible(&dev->mutex)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
}
|
||||
@ -602,7 +602,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
|
||||
|
||||
unlock_exit:
|
||||
/* unlock the device */
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
@ -651,7 +651,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
dev_err(&intf->dev, "Out of memory\n");
|
||||
goto exit;
|
||||
}
|
||||
init_MUTEX(&dev->sem);
|
||||
mutex_init(&dev->mutex);
|
||||
spin_lock_init(&dev->rbsl);
|
||||
dev->intf = intf;
|
||||
init_waitqueue_head(&dev->read_wait);
|
||||
@ -765,15 +765,15 @@ static void ld_usb_disconnect(struct usb_interface *intf)
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(intf, &ld_usb_class);
|
||||
|
||||
down(&dev->sem);
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
if (!dev->open_count) {
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
ld_usb_delete(dev);
|
||||
} else {
|
||||
dev->intf = NULL;
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
|
||||
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
|
||||
|
@ -79,30 +79,10 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
|
||||
/* set up all urbs so they can be used with either bulk or interrupt */
|
||||
#define INTERRUPT_RATE 1 /* msec/transfer */
|
||||
|
||||
#define xprintk(tdev,level,fmt,args...) \
|
||||
dev_printk(level , &(tdev)->intf->dev , fmt , ## args)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(dev,fmt,args...) \
|
||||
xprintk(dev , KERN_DEBUG , fmt , ## args)
|
||||
#else
|
||||
#define DBG(dev,fmt,args...) \
|
||||
do { } while (0)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef VERBOSE
|
||||
#define VDBG DBG
|
||||
#else
|
||||
#define VDBG(dev,fmt,args...) \
|
||||
do { } while (0)
|
||||
#endif /* VERBOSE */
|
||||
|
||||
#define ERROR(dev,fmt,args...) \
|
||||
xprintk(dev , KERN_ERR , fmt , ## args)
|
||||
#define WARN(dev,fmt,args...) \
|
||||
xprintk(dev , KERN_WARNING , fmt , ## args)
|
||||
#define INFO(dev,fmt,args...) \
|
||||
xprintk(dev , KERN_INFO , fmt , ## args)
|
||||
#define ERROR(tdev, fmt, args...) \
|
||||
dev_err(&(tdev)->intf->dev , fmt , ## args)
|
||||
#define WARN(tdev, fmt, args...) \
|
||||
dev_warn(&(tdev)->intf->dev , fmt , ## args)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -236,7 +216,7 @@ static struct urb *simple_alloc_urb (
|
||||
|
||||
static unsigned pattern = 0;
|
||||
module_param (pattern, uint, S_IRUGO);
|
||||
// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
|
||||
MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
|
||||
|
||||
static inline void simple_fill_buf (struct urb *urb)
|
||||
{
|
||||
@ -257,7 +237,7 @@ static inline void simple_fill_buf (struct urb *urb)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int simple_check_buf (struct urb *urb)
|
||||
static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
|
||||
{
|
||||
unsigned i;
|
||||
u8 expected;
|
||||
@ -285,7 +265,7 @@ static inline int simple_check_buf (struct urb *urb)
|
||||
}
|
||||
if (*buf == expected)
|
||||
continue;
|
||||
dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
|
||||
ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@ -299,6 +279,7 @@ static void simple_free_urb (struct urb *urb)
|
||||
}
|
||||
|
||||
static int simple_io (
|
||||
struct usbtest_dev *tdev,
|
||||
struct urb *urb,
|
||||
int iterations,
|
||||
int vary,
|
||||
@ -324,7 +305,7 @@ static int simple_io (
|
||||
retval = urb->status;
|
||||
urb->dev = udev;
|
||||
if (retval == 0 && usb_pipein (urb->pipe))
|
||||
retval = simple_check_buf (urb);
|
||||
retval = simple_check_buf(tdev, urb);
|
||||
|
||||
if (vary) {
|
||||
int len = urb->transfer_buffer_length;
|
||||
@ -341,7 +322,7 @@ static int simple_io (
|
||||
urb->transfer_buffer_length = max;
|
||||
|
||||
if (expected != retval)
|
||||
dev_dbg (&udev->dev,
|
||||
dev_err(&udev->dev,
|
||||
"%s failed, iterations left %d, status %d (not %d)\n",
|
||||
label, iterations, retval, expected);
|
||||
return retval;
|
||||
@ -357,7 +338,7 @@ static int simple_io (
|
||||
static void free_sglist (struct scatterlist *sg, int nents)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
|
||||
if (!sg)
|
||||
return;
|
||||
for (i = 0; i < nents; i++) {
|
||||
@ -415,7 +396,7 @@ alloc_sglist (int nents, int max, int vary)
|
||||
}
|
||||
|
||||
static int perform_sglist (
|
||||
struct usb_device *udev,
|
||||
struct usbtest_dev *tdev,
|
||||
unsigned iterations,
|
||||
int pipe,
|
||||
struct usb_sg_request *req,
|
||||
@ -423,6 +404,7 @@ static int perform_sglist (
|
||||
int nents
|
||||
)
|
||||
{
|
||||
struct usb_device *udev = testdev_to_usbdev(tdev);
|
||||
int retval = 0;
|
||||
|
||||
while (retval == 0 && iterations-- > 0) {
|
||||
@ -431,7 +413,7 @@ static int perform_sglist (
|
||||
? (INTERRUPT_RATE << 3)
|
||||
: INTERRUPT_RATE,
|
||||
sg, nents, 0, GFP_KERNEL);
|
||||
|
||||
|
||||
if (retval)
|
||||
break;
|
||||
usb_sg_wait (req);
|
||||
@ -446,7 +428,8 @@ static int perform_sglist (
|
||||
// failure if retval is as we expected ...
|
||||
|
||||
if (retval)
|
||||
dbg ("perform_sglist failed, iterations left %d, status %d",
|
||||
ERROR(tdev, "perform_sglist failed, "
|
||||
"iterations left %d, status %d\n",
|
||||
iterations, retval);
|
||||
return retval;
|
||||
}
|
||||
@ -505,28 +488,28 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate)
|
||||
alternate);
|
||||
}
|
||||
|
||||
static int is_good_config (char *buf, int len)
|
||||
static int is_good_config(struct usbtest_dev *tdev, int len)
|
||||
{
|
||||
struct usb_config_descriptor *config;
|
||||
|
||||
|
||||
if (len < sizeof *config)
|
||||
return 0;
|
||||
config = (struct usb_config_descriptor *) buf;
|
||||
config = (struct usb_config_descriptor *) tdev->buf;
|
||||
|
||||
switch (config->bDescriptorType) {
|
||||
case USB_DT_CONFIG:
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
if (config->bLength != 9) {
|
||||
dbg ("bogus config descriptor length");
|
||||
ERROR(tdev, "bogus config descriptor length\n");
|
||||
return 0;
|
||||
}
|
||||
/* this bit 'must be 1' but often isn't */
|
||||
if (!realworld && !(config->bmAttributes & 0x80)) {
|
||||
dbg ("high bit of config attributes not set");
|
||||
ERROR(tdev, "high bit of config attributes not set\n");
|
||||
return 0;
|
||||
}
|
||||
if (config->bmAttributes & 0x1f) { /* reserved == 0 */
|
||||
dbg ("reserved config bits set");
|
||||
ERROR(tdev, "reserved config bits set\n");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -538,7 +521,7 @@ static int is_good_config (char *buf, int len)
|
||||
return 1;
|
||||
if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */
|
||||
return 1;
|
||||
dbg ("bogus config descriptor read size");
|
||||
ERROR(tdev, "bogus config descriptor read size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -571,7 +554,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
/* 9.2.3 constrains the range here */
|
||||
alt = iface->altsetting [i].desc.bAlternateSetting;
|
||||
if (alt < 0 || alt >= iface->num_altsetting) {
|
||||
dev_dbg (&iface->dev,
|
||||
dev_err(&iface->dev,
|
||||
"invalid alt [%d].bAltSetting = %d\n",
|
||||
i, alt);
|
||||
}
|
||||
@ -583,7 +566,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
/* [9.4.10] set_interface */
|
||||
retval = set_altsetting (dev, alt);
|
||||
if (retval) {
|
||||
dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
|
||||
dev_err(&iface->dev, "can't set_interface = %d, %d\n",
|
||||
alt, retval);
|
||||
return retval;
|
||||
}
|
||||
@ -591,7 +574,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
/* [9.4.4] get_interface always works */
|
||||
retval = get_altsetting (dev);
|
||||
if (retval != alt) {
|
||||
dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
|
||||
dev_err(&iface->dev, "get alt should be %d, was %d\n",
|
||||
alt, retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
@ -611,7 +594,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
|
||||
if (retval != 1 || dev->buf [0] != expected) {
|
||||
dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
|
||||
dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
|
||||
retval, dev->buf[0], expected);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
@ -621,7 +604,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
|
||||
dev->buf, sizeof udev->descriptor);
|
||||
if (retval != sizeof udev->descriptor) {
|
||||
dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
|
||||
dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
|
||||
@ -629,8 +612,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
|
||||
retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
|
||||
dev->buf, TBUF_SIZE);
|
||||
if (!is_good_config (dev->buf, retval)) {
|
||||
dev_dbg (&iface->dev,
|
||||
if (!is_good_config(dev, retval)) {
|
||||
dev_err(&iface->dev,
|
||||
"config [%d] descriptor --> %d\n",
|
||||
i, retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
@ -650,14 +633,14 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
sizeof (struct usb_qualifier_descriptor));
|
||||
if (retval == -EPIPE) {
|
||||
if (udev->speed == USB_SPEED_HIGH) {
|
||||
dev_dbg (&iface->dev,
|
||||
dev_err(&iface->dev,
|
||||
"hs dev qualifier --> %d\n",
|
||||
retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
/* usb2.0 but not high-speed capable; fine */
|
||||
} else if (retval != sizeof (struct usb_qualifier_descriptor)) {
|
||||
dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
|
||||
dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
} else
|
||||
d = (struct usb_qualifier_descriptor *) dev->buf;
|
||||
@ -669,8 +652,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
retval = usb_get_descriptor (udev,
|
||||
USB_DT_OTHER_SPEED_CONFIG, i,
|
||||
dev->buf, TBUF_SIZE);
|
||||
if (!is_good_config (dev->buf, retval)) {
|
||||
dev_dbg (&iface->dev,
|
||||
if (!is_good_config(dev, retval)) {
|
||||
dev_err(&iface->dev,
|
||||
"other speed config --> %d\n",
|
||||
retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
@ -683,7 +666,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
/* [9.4.5] get_status always works */
|
||||
retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
|
||||
if (retval != 2) {
|
||||
dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
|
||||
dev_err(&iface->dev, "get dev status --> %d\n", retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
|
||||
@ -693,11 +676,11 @@ static int ch9_postconfig (struct usbtest_dev *dev)
|
||||
retval = usb_get_status (udev, USB_RECIP_INTERFACE,
|
||||
iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
|
||||
if (retval != 2) {
|
||||
dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
|
||||
dev_err(&iface->dev, "get interface status --> %d\n", retval);
|
||||
return (retval < 0) ? retval : -EDOM;
|
||||
}
|
||||
// FIXME get status for each endpoint in the interface
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -752,8 +735,9 @@ static void ctrl_complete (struct urb *urb)
|
||||
*/
|
||||
if (subcase->number > 0) {
|
||||
if ((subcase->number - ctx->last) != 1) {
|
||||
dbg ("subcase %d completed out of order, last %d",
|
||||
subcase->number, ctx->last);
|
||||
ERROR(ctx->dev,
|
||||
"subcase %d completed out of order, last %d\n",
|
||||
subcase->number, ctx->last);
|
||||
status = -EDOM;
|
||||
ctx->last = subcase->number;
|
||||
goto error;
|
||||
@ -777,7 +761,7 @@ static void ctrl_complete (struct urb *urb)
|
||||
else if (subcase->number == 12 && status == -EPIPE)
|
||||
status = 0;
|
||||
else
|
||||
dbg ("subtest %d error, status %d",
|
||||
ERROR(ctx->dev, "subtest %d error, status %d\n",
|
||||
subcase->number, status);
|
||||
}
|
||||
|
||||
@ -788,9 +772,12 @@ error:
|
||||
int i;
|
||||
|
||||
ctx->status = status;
|
||||
info ("control queue %02x.%02x, err %d, %d left",
|
||||
ERROR(ctx->dev, "control queue %02x.%02x, err %d, "
|
||||
"%d left, subcase %d, len %d/%d\n",
|
||||
reqp->bRequestType, reqp->bRequest,
|
||||
status, ctx->count);
|
||||
status, ctx->count, subcase->number,
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length);
|
||||
|
||||
/* FIXME this "unlink everything" exit route should
|
||||
* be a separate test case.
|
||||
@ -799,7 +786,8 @@ error:
|
||||
/* unlink whatever's still pending */
|
||||
for (i = 1; i < ctx->param->sglen; i++) {
|
||||
struct urb *u = ctx->urb [
|
||||
(i + subcase->number) % ctx->param->sglen];
|
||||
(i + subcase->number)
|
||||
% ctx->param->sglen];
|
||||
|
||||
if (u == urb || !u->dev)
|
||||
continue;
|
||||
@ -812,7 +800,8 @@ error:
|
||||
case -EIDRM:
|
||||
continue;
|
||||
default:
|
||||
dbg ("urb unlink --> %d", status);
|
||||
ERROR(ctx->dev, "urb unlink --> %d\n",
|
||||
status);
|
||||
}
|
||||
}
|
||||
status = ctx->status;
|
||||
@ -822,14 +811,15 @@ error:
|
||||
/* resubmit if we need to, else mark this as done */
|
||||
if ((status == 0) && (ctx->pending < ctx->count)) {
|
||||
if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
|
||||
dbg ("can't resubmit ctrl %02x.%02x, err %d",
|
||||
ERROR(ctx->dev,
|
||||
"can't resubmit ctrl %02x.%02x, err %d\n",
|
||||
reqp->bRequestType, reqp->bRequest, status);
|
||||
urb->dev = NULL;
|
||||
} else
|
||||
ctx->pending++;
|
||||
} else
|
||||
urb->dev = NULL;
|
||||
|
||||
|
||||
/* signal completion when nothing's queued */
|
||||
if (ctx->pending == 0)
|
||||
complete (&ctx->complete);
|
||||
@ -918,11 +908,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
|
||||
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
|
||||
// interface == 0
|
||||
len = sizeof (struct usb_interface_descriptor);
|
||||
expected = EPIPE;
|
||||
expected = -EPIPE;
|
||||
break;
|
||||
// NOTE: two consecutive stalls in the queue here.
|
||||
// that tests fault recovery a bit more aggressively.
|
||||
case 8: // clear endpoint halt (USUALLY STALLS)
|
||||
case 8: // clear endpoint halt (MAY STALL)
|
||||
req.bRequest = USB_REQ_CLEAR_FEATURE;
|
||||
req.bRequestType = USB_RECIP_ENDPOINT;
|
||||
// wValue 0 == ep halt
|
||||
@ -965,7 +955,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
|
||||
break;
|
||||
case 14: // short read; try to fill the last packet
|
||||
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
|
||||
// device descriptor size == 18 bytes
|
||||
/* device descriptor size == 18 bytes */
|
||||
len = udev->descriptor.bMaxPacketSize0;
|
||||
switch (len) {
|
||||
case 8: len = 24; break;
|
||||
@ -974,7 +964,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
|
||||
expected = -EREMOTEIO;
|
||||
break;
|
||||
default:
|
||||
err ("bogus number of ctrl queue testcases!");
|
||||
ERROR(dev, "bogus number of ctrl queue testcases!\n");
|
||||
context.status = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -1003,7 +993,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
|
||||
for (i = 0; i < param->sglen; i++) {
|
||||
context.status = usb_submit_urb (urb [i], GFP_ATOMIC);
|
||||
if (context.status != 0) {
|
||||
dbg ("can't submit urb[%d], status %d",
|
||||
ERROR(dev, "can't submit urb[%d], status %d\n",
|
||||
i, context.status);
|
||||
context.count = context.pending;
|
||||
break;
|
||||
@ -1070,7 +1060,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
|
||||
* due to errors, or is just NAKing requests.
|
||||
*/
|
||||
if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) {
|
||||
dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
|
||||
dev_err(&dev->intf->dev, "submit fail %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1087,13 +1077,13 @@ retry:
|
||||
* "normal" drivers would prevent resubmission, but
|
||||
* since we're testing unlink paths, we can't.
|
||||
*/
|
||||
dev_dbg (&dev->intf->dev, "unlink retry\n");
|
||||
ERROR(dev, "unlink retry\n");
|
||||
goto retry;
|
||||
}
|
||||
} else
|
||||
usb_kill_urb (urb);
|
||||
if (!(retval == 0 || retval == -EINPROGRESS)) {
|
||||
dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
|
||||
dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1121,7 +1111,7 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int verify_not_halted (int ep, struct urb *urb)
|
||||
static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
|
||||
{
|
||||
int retval;
|
||||
u16 status;
|
||||
@ -1129,20 +1119,21 @@ static int verify_not_halted (int ep, struct urb *urb)
|
||||
/* shouldn't look or act halted */
|
||||
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
|
||||
if (retval < 0) {
|
||||
dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
|
||||
ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
|
||||
ep, retval);
|
||||
return retval;
|
||||
}
|
||||
if (status != 0) {
|
||||
dbg ("ep %02x bogus status: %04x != 0", ep, status);
|
||||
ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
|
||||
return -EINVAL;
|
||||
}
|
||||
retval = simple_io (urb, 1, 0, 0, __func__);
|
||||
retval = simple_io(tdev, urb, 1, 0, 0, __func__);
|
||||
if (retval != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_halted (int ep, struct urb *urb)
|
||||
static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
|
||||
{
|
||||
int retval;
|
||||
u16 status;
|
||||
@ -1150,29 +1141,30 @@ static int verify_halted (int ep, struct urb *urb)
|
||||
/* should look and act halted */
|
||||
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
|
||||
if (retval < 0) {
|
||||
dbg ("ep %02x couldn't get halt status, %d", ep, retval);
|
||||
ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
|
||||
ep, retval);
|
||||
return retval;
|
||||
}
|
||||
le16_to_cpus(&status);
|
||||
if (status != 1) {
|
||||
dbg ("ep %02x bogus status: %04x != 1", ep, status);
|
||||
ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
|
||||
return -EINVAL;
|
||||
}
|
||||
retval = simple_io (urb, 1, 0, -EPIPE, __func__);
|
||||
retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
|
||||
if (retval != -EPIPE)
|
||||
return -EINVAL;
|
||||
retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
|
||||
retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
|
||||
if (retval != -EPIPE)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_halt (int ep, struct urb *urb)
|
||||
static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* shouldn't look or act halted now */
|
||||
retval = verify_not_halted (ep, urb);
|
||||
retval = verify_not_halted(tdev, ep, urb);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
@ -1182,20 +1174,20 @@ static int test_halt (int ep, struct urb *urb)
|
||||
USB_ENDPOINT_HALT, ep,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (retval < 0) {
|
||||
dbg ("ep %02x couldn't set halt, %d", ep, retval);
|
||||
ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
|
||||
return retval;
|
||||
}
|
||||
retval = verify_halted (ep, urb);
|
||||
retval = verify_halted(tdev, ep, urb);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/* clear halt (tests API + protocol), verify it worked */
|
||||
retval = usb_clear_halt (urb->dev, urb->pipe);
|
||||
if (retval < 0) {
|
||||
dbg ("ep %02x couldn't clear halt, %d", ep, retval);
|
||||
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
|
||||
return retval;
|
||||
}
|
||||
retval = verify_not_halted (ep, urb);
|
||||
retval = verify_not_halted(tdev, ep, urb);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
@ -1217,7 +1209,7 @@ static int halt_simple (struct usbtest_dev *dev)
|
||||
if (dev->in_pipe) {
|
||||
ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
|
||||
urb->pipe = dev->in_pipe;
|
||||
retval = test_halt (ep, urb);
|
||||
retval = test_halt(dev, ep, urb);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
}
|
||||
@ -1225,7 +1217,7 @@ static int halt_simple (struct usbtest_dev *dev)
|
||||
if (dev->out_pipe) {
|
||||
ep = usb_pipeendpoint (dev->out_pipe);
|
||||
urb->pipe = dev->out_pipe;
|
||||
retval = test_halt (ep, urb);
|
||||
retval = test_halt(dev, ep, urb);
|
||||
}
|
||||
done:
|
||||
simple_free_urb (urb);
|
||||
@ -1275,7 +1267,7 @@ static int ctrl_out (struct usbtest_dev *dev,
|
||||
if (retval != len) {
|
||||
what = "write";
|
||||
if (retval >= 0) {
|
||||
INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
|
||||
ERROR(dev, "ctrl_out, wlen %d (expected %d)\n",
|
||||
retval, len);
|
||||
retval = -EBADMSG;
|
||||
}
|
||||
@ -1289,7 +1281,7 @@ static int ctrl_out (struct usbtest_dev *dev,
|
||||
if (retval != len) {
|
||||
what = "read";
|
||||
if (retval >= 0) {
|
||||
INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
|
||||
ERROR(dev, "ctrl_out, rlen %d (expected %d)\n",
|
||||
retval, len);
|
||||
retval = -EBADMSG;
|
||||
}
|
||||
@ -1299,7 +1291,7 @@ static int ctrl_out (struct usbtest_dev *dev,
|
||||
/* fail if we can't verify */
|
||||
for (j = 0; j < len; j++) {
|
||||
if (buf [j] != (u8) (i + j)) {
|
||||
INFO (dev, "ctrl_out, byte %d is %d not %d\n",
|
||||
ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
|
||||
j, buf [j], (u8) i + j);
|
||||
retval = -EBADMSG;
|
||||
break;
|
||||
@ -1321,7 +1313,7 @@ static int ctrl_out (struct usbtest_dev *dev,
|
||||
}
|
||||
|
||||
if (retval < 0)
|
||||
INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
|
||||
ERROR (dev, "ctrl_out %s failed, code %d, count %d\n",
|
||||
what, retval, i);
|
||||
|
||||
kfree (buf);
|
||||
@ -1366,7 +1358,7 @@ static void iso_callback (struct urb *urb)
|
||||
case 0:
|
||||
goto done;
|
||||
default:
|
||||
dev_dbg (&ctx->dev->intf->dev,
|
||||
dev_err(&ctx->dev->intf->dev,
|
||||
"iso resubmit err %d\n",
|
||||
status);
|
||||
/* FALLTHROUGH */
|
||||
@ -1381,7 +1373,7 @@ static void iso_callback (struct urb *urb)
|
||||
ctx->pending--;
|
||||
if (ctx->pending == 0) {
|
||||
if (ctx->errors)
|
||||
dev_dbg (&ctx->dev->intf->dev,
|
||||
dev_err(&ctx->dev->intf->dev,
|
||||
"iso test, %lu errors out of %lu\n",
|
||||
ctx->errors, ctx->packet_count);
|
||||
complete (&ctx->done);
|
||||
@ -1458,7 +1450,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
|
||||
|
||||
memset (urbs, 0, sizeof urbs);
|
||||
udev = testdev_to_usbdev (dev);
|
||||
dev_dbg (&dev->intf->dev,
|
||||
dev_info(&dev->intf->dev,
|
||||
"... iso period %d %sframes, wMaxPacket %04x\n",
|
||||
1 << (desc->bInterval - 1),
|
||||
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
||||
@ -1475,7 +1467,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
|
||||
urbs [i]->context = &context;
|
||||
}
|
||||
packets *= param->iterations;
|
||||
dev_dbg (&dev->intf->dev,
|
||||
dev_info(&dev->intf->dev,
|
||||
"... total %lu msec (%lu packets)\n",
|
||||
(packets * (1 << (desc->bInterval - 1)))
|
||||
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
||||
@ -1537,6 +1529,13 @@ fail:
|
||||
* except indirectly by consuming USB bandwidth and CPU resources for test
|
||||
* threads and request completion. But the only way to know that for sure
|
||||
* is to test when HC queues are in use by many devices.
|
||||
*
|
||||
* WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
|
||||
* it locks out usbcore in certain code paths. Notably, if you disconnect
|
||||
* the device-under-test, khubd will wait block forever waiting for the
|
||||
* ioctl to complete ... so that usb_disconnect() can abort the pending
|
||||
* urbs and then call usbtest_disconnect(). To abort a test, you're best
|
||||
* off just killing the userspace task and waiting for it to exit.
|
||||
*/
|
||||
|
||||
static int
|
||||
@ -1575,7 +1574,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
* altsettings; force a default so most tests don't need to check.
|
||||
*/
|
||||
if (dev->info->alt >= 0) {
|
||||
int res;
|
||||
int res;
|
||||
|
||||
if (intf->altsetting->desc.bInterfaceNumber) {
|
||||
mutex_unlock(&dev->lock);
|
||||
@ -1604,7 +1603,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
switch (param->test_num) {
|
||||
|
||||
case 0:
|
||||
dev_dbg (&intf->dev, "TEST 0: NOP\n");
|
||||
dev_info(&intf->dev, "TEST 0: NOP\n");
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
@ -1612,7 +1611,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
case 1:
|
||||
if (dev->out_pipe == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 1: write %d bytes %u times\n",
|
||||
param->length, param->iterations);
|
||||
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
|
||||
@ -1621,13 +1620,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk sink (maybe accepts short writes)
|
||||
retval = simple_io (urb, param->iterations, 0, 0, "test1");
|
||||
retval = simple_io(dev, urb, param->iterations, 0, 0, "test1");
|
||||
simple_free_urb (urb);
|
||||
break;
|
||||
case 2:
|
||||
if (dev->in_pipe == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 2: read %d bytes %u times\n",
|
||||
param->length, param->iterations);
|
||||
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
|
||||
@ -1636,13 +1635,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk source (maybe generates short writes)
|
||||
retval = simple_io (urb, param->iterations, 0, 0, "test2");
|
||||
retval = simple_io(dev, urb, param->iterations, 0, 0, "test2");
|
||||
simple_free_urb (urb);
|
||||
break;
|
||||
case 3:
|
||||
if (dev->out_pipe == 0 || param->vary == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 3: write/%d 0..%d bytes %u times\n",
|
||||
param->vary, param->length, param->iterations);
|
||||
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
|
||||
@ -1651,14 +1650,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk sink (maybe accepts short writes)
|
||||
retval = simple_io (urb, param->iterations, param->vary,
|
||||
retval = simple_io(dev, urb, param->iterations, param->vary,
|
||||
0, "test3");
|
||||
simple_free_urb (urb);
|
||||
break;
|
||||
case 4:
|
||||
if (dev->in_pipe == 0 || param->vary == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 4: read/%d 0..%d bytes %u times\n",
|
||||
param->vary, param->length, param->iterations);
|
||||
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
|
||||
@ -1667,7 +1666,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk source (maybe generates short writes)
|
||||
retval = simple_io (urb, param->iterations, param->vary,
|
||||
retval = simple_io(dev, urb, param->iterations, param->vary,
|
||||
0, "test4");
|
||||
simple_free_urb (urb);
|
||||
break;
|
||||
@ -1676,7 +1675,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
case 5:
|
||||
if (dev->out_pipe == 0 || param->sglen == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 5: write %d sglists %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1686,7 +1685,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk sink (maybe accepts short writes)
|
||||
retval = perform_sglist (udev, param->iterations, dev->out_pipe,
|
||||
retval = perform_sglist(dev, param->iterations, dev->out_pipe,
|
||||
&req, sg, param->sglen);
|
||||
free_sglist (sg, param->sglen);
|
||||
break;
|
||||
@ -1694,7 +1693,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
case 6:
|
||||
if (dev->in_pipe == 0 || param->sglen == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 6: read %d sglists %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1704,14 +1703,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk source (maybe generates short writes)
|
||||
retval = perform_sglist (udev, param->iterations, dev->in_pipe,
|
||||
retval = perform_sglist(dev, param->iterations, dev->in_pipe,
|
||||
&req, sg, param->sglen);
|
||||
free_sglist (sg, param->sglen);
|
||||
break;
|
||||
case 7:
|
||||
if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
|
||||
param->vary, param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1721,14 +1720,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk sink (maybe accepts short writes)
|
||||
retval = perform_sglist (udev, param->iterations, dev->out_pipe,
|
||||
retval = perform_sglist(dev, param->iterations, dev->out_pipe,
|
||||
&req, sg, param->sglen);
|
||||
free_sglist (sg, param->sglen);
|
||||
break;
|
||||
case 8:
|
||||
if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
|
||||
param->vary, param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1738,7 +1737,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
break;
|
||||
}
|
||||
// FIRMWARE: bulk source (maybe generates short writes)
|
||||
retval = perform_sglist (udev, param->iterations, dev->in_pipe,
|
||||
retval = perform_sglist(dev, param->iterations, dev->in_pipe,
|
||||
&req, sg, param->sglen);
|
||||
free_sglist (sg, param->sglen);
|
||||
break;
|
||||
@ -1746,13 +1745,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
/* non-queued sanity tests for control (chapter 9 subset) */
|
||||
case 9:
|
||||
retval = 0;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 9: ch9 (subset) control tests, %d times\n",
|
||||
param->iterations);
|
||||
for (i = param->iterations; retval == 0 && i--; /* NOP */)
|
||||
retval = ch9_postconfig (dev);
|
||||
if (retval)
|
||||
dbg ("ch9 subset failed, iterations left %d", i);
|
||||
dev_err(&intf->dev, "ch9 subset failed, "
|
||||
"iterations left %d\n", i);
|
||||
break;
|
||||
|
||||
/* queued control messaging */
|
||||
@ -1760,7 +1760,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
if (param->sglen == 0)
|
||||
break;
|
||||
retval = 0;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 10: queue %d control calls, %d times\n",
|
||||
param->sglen,
|
||||
param->iterations);
|
||||
@ -1772,26 +1772,26 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
if (dev->in_pipe == 0 || !param->length)
|
||||
break;
|
||||
retval = 0;
|
||||
dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n",
|
||||
dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n",
|
||||
param->iterations, param->length);
|
||||
for (i = param->iterations; retval == 0 && i--; /* NOP */)
|
||||
retval = unlink_simple (dev, dev->in_pipe,
|
||||
param->length);
|
||||
if (retval)
|
||||
dev_dbg (&intf->dev, "unlink reads failed %d, "
|
||||
dev_err(&intf->dev, "unlink reads failed %d, "
|
||||
"iterations left %d\n", retval, i);
|
||||
break;
|
||||
case 12:
|
||||
if (dev->out_pipe == 0 || !param->length)
|
||||
break;
|
||||
retval = 0;
|
||||
dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n",
|
||||
dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n",
|
||||
param->iterations, param->length);
|
||||
for (i = param->iterations; retval == 0 && i--; /* NOP */)
|
||||
retval = unlink_simple (dev, dev->out_pipe,
|
||||
param->length);
|
||||
if (retval)
|
||||
dev_dbg (&intf->dev, "unlink writes failed %d, "
|
||||
dev_err(&intf->dev, "unlink writes failed %d, "
|
||||
"iterations left %d\n", retval, i);
|
||||
break;
|
||||
|
||||
@ -1800,24 +1800,24 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
if (dev->out_pipe == 0 && dev->in_pipe == 0)
|
||||
break;
|
||||
retval = 0;
|
||||
dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n",
|
||||
dev_info(&intf->dev, "TEST 13: set/clear %d halts\n",
|
||||
param->iterations);
|
||||
for (i = param->iterations; retval == 0 && i--; /* NOP */)
|
||||
retval = halt_simple (dev);
|
||||
|
||||
|
||||
if (retval)
|
||||
DBG (dev, "halts failed, iterations left %d\n", i);
|
||||
ERROR(dev, "halts failed, iterations left %d\n", i);
|
||||
break;
|
||||
|
||||
/* control write tests */
|
||||
case 14:
|
||||
if (!dev->info->ctrl_out)
|
||||
break;
|
||||
dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
|
||||
dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
|
||||
param->iterations,
|
||||
realworld ? 1 : 0, param->length,
|
||||
param->vary);
|
||||
retval = ctrl_out (dev, param->iterations,
|
||||
retval = ctrl_out(dev, param->iterations,
|
||||
param->length, param->vary);
|
||||
break;
|
||||
|
||||
@ -1825,7 +1825,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
case 15:
|
||||
if (dev->out_iso_pipe == 0 || param->sglen == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 15: write %d iso, %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1838,7 +1838,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
|
||||
case 16:
|
||||
if (dev->in_iso_pipe == 0 || param->sglen == 0)
|
||||
break;
|
||||
dev_dbg (&intf->dev,
|
||||
dev_info(&intf->dev,
|
||||
"TEST 16: read %d iso, %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
@ -1898,7 +1898,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
|
||||
return -ENODEV;
|
||||
if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
|
||||
return -ENODEV;
|
||||
dbg ("matched module params, vend=0x%04x prod=0x%04x",
|
||||
dev_info(&intf->dev, "matched module params, "
|
||||
"vend=0x%04x prod=0x%04x\n",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
}
|
||||
@ -1940,7 +1941,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
|
||||
|
||||
status = get_endpoints (dev, intf);
|
||||
if (status < 0) {
|
||||
dbg ("couldn't get endpoints, %d\n", status);
|
||||
WARN(dev, "couldn't get endpoints, %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
/* may find bulk or ISO pipes */
|
||||
@ -2082,21 +2084,9 @@ static struct usbtest_info generic_info = {
|
||||
};
|
||||
#endif
|
||||
|
||||
// FIXME remove this
|
||||
static struct usbtest_info hact_info = {
|
||||
.name = "FX2/hact",
|
||||
//.ep_in = 6,
|
||||
.ep_out = 2,
|
||||
.alt = -1,
|
||||
};
|
||||
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
|
||||
{ USB_DEVICE (0x0547, 0x1002),
|
||||
.driver_info = (unsigned long) &hact_info,
|
||||
},
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* EZ-USB devices which download firmware to replace (or in our
|
||||
@ -2185,7 +2175,7 @@ static int __init usbtest_init (void)
|
||||
{
|
||||
#ifdef GENERIC
|
||||
if (vendor)
|
||||
dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
|
||||
pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product);
|
||||
#endif
|
||||
return usb_register (&usbtest_driver);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ static void serial_buf_free(struct circ_buf *cb)
|
||||
*/
|
||||
static int serial_buf_data_avail(struct circ_buf *cb)
|
||||
{
|
||||
return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
|
||||
return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -171,7 +171,7 @@ static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
|
||||
cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
|
||||
buf += c;
|
||||
count -= c;
|
||||
ret= c;
|
||||
ret = c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -197,7 +197,7 @@ static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
|
||||
cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
|
||||
buf += c;
|
||||
count -= c;
|
||||
ret= c;
|
||||
ret = c;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -208,7 +208,7 @@ static void aircable_send(struct usb_serial_port *port)
|
||||
{
|
||||
int count, result;
|
||||
struct aircable_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned char* buf;
|
||||
unsigned char *buf;
|
||||
__le16 *dbuf;
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
if (port->write_urb_busy)
|
||||
@ -229,7 +229,8 @@ static void aircable_send(struct usb_serial_port *port)
|
||||
buf[1] = TX_HEADER_1;
|
||||
dbuf = (__le16 *)&buf[2];
|
||||
*dbuf = cpu_to_le16((u16)count);
|
||||
serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
|
||||
serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
|
||||
MAX_HCI_FRAMESIZE);
|
||||
|
||||
memcpy(port->write_urb->transfer_buffer, buf,
|
||||
count + HCI_HEADER_LENGTH);
|
||||
@ -261,7 +262,7 @@ static void aircable_read(struct work_struct *work)
|
||||
struct tty_struct *tty;
|
||||
unsigned char *data;
|
||||
int count;
|
||||
if (priv->rx_flags & THROTTLED){
|
||||
if (priv->rx_flags & THROTTLED) {
|
||||
if (priv->rx_flags & ACTUALLY_THROTTLED)
|
||||
schedule_work(&priv->rx_work);
|
||||
return;
|
||||
@ -282,10 +283,10 @@ static void aircable_read(struct work_struct *work)
|
||||
count = min(64, serial_buf_data_avail(priv->rx_buf));
|
||||
|
||||
if (count <= 0)
|
||||
return; //We have finished sending everything.
|
||||
return; /* We have finished sending everything. */
|
||||
|
||||
tty_prepare_flip_string(tty, &data, count);
|
||||
if (!data){
|
||||
if (!data) {
|
||||
err("%s- kzalloc(%d) failed.", __func__, count);
|
||||
return;
|
||||
}
|
||||
@ -304,9 +305,10 @@ static void aircable_read(struct work_struct *work)
|
||||
static int aircable_probe(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
|
||||
struct usb_host_interface *iface_desc = serial->interface->
|
||||
cur_altsetting;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int num_bulk_out=0;
|
||||
int num_bulk_out = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
|
||||
@ -325,13 +327,13 @@ static int aircable_probe(struct usb_serial *serial,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aircable_attach (struct usb_serial *serial)
|
||||
static int aircable_attach(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_serial_port *port = serial->port[0];
|
||||
struct aircable_private *priv;
|
||||
|
||||
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
|
||||
if (!priv){
|
||||
if (!priv) {
|
||||
err("%s- kmalloc(%Zd) failed.", __func__,
|
||||
sizeof(struct aircable_private));
|
||||
return -ENOMEM;
|
||||
@ -392,7 +394,7 @@ static int aircable_write(struct usb_serial_port *port,
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev, __func__, count, source);
|
||||
|
||||
if (!count){
|
||||
if (!count) {
|
||||
dbg("%s - write request of 0 bytes", __func__);
|
||||
return count;
|
||||
}
|
||||
@ -418,31 +420,31 @@ static void aircable_write_bulk_callback(struct urb *urb)
|
||||
|
||||
/* This has been taken from cypress_m8.c cypress_write_int_callback */
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__func__, status);
|
||||
port->write_urb_busy = 0;
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__func__, status);
|
||||
port->write_urb_busy = 0;
|
||||
return;
|
||||
default:
|
||||
/* error in the urb, so we have to resubmit it */
|
||||
dbg("%s - Overflow in write", __func__);
|
||||
dbg("%s - nonzero write bulk status received: %d",
|
||||
__func__, status);
|
||||
port->write_urb->transfer_buffer_length = 1;
|
||||
port->write_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&urb->dev->dev,
|
||||
"%s - failed resubmitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
else
|
||||
return;
|
||||
default:
|
||||
/* error in the urb, so we have to resubmit it */
|
||||
dbg("%s - Overflow in write", __func__);
|
||||
dbg("%s - nonzero write bulk status received: %d",
|
||||
__func__, status);
|
||||
port->write_urb->transfer_buffer_length = 1;
|
||||
port->write_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&urb->dev->dev,
|
||||
"%s - failed resubmitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
port->write_urb_busy = 0;
|
||||
@ -472,11 +474,11 @@ static void aircable_read_bulk_callback(struct urb *urb)
|
||||
dbg("%s - caught -EPROTO, resubmitting the urb",
|
||||
__func__);
|
||||
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
|
||||
usb_rcvbulkpipe(port->serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
port->read_urb->transfer_buffer,
|
||||
port->read_urb->transfer_buffer_length,
|
||||
aircable_read_bulk_callback, port);
|
||||
usb_rcvbulkpipe(port->serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
port->read_urb->transfer_buffer,
|
||||
port->read_urb->transfer_buffer_length,
|
||||
aircable_read_bulk_callback, port);
|
||||
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
@ -490,7 +492,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
|
||||
}
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev, __func__,
|
||||
urb->actual_length,urb->transfer_buffer);
|
||||
urb->actual_length, urb->transfer_buffer);
|
||||
|
||||
tty = port->tty;
|
||||
if (tty && urb->actual_length) {
|
||||
@ -507,9 +509,9 @@ static void aircable_read_bulk_callback(struct urb *urb)
|
||||
no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
|
||||
|
||||
if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
|
||||
no_packages+=1;
|
||||
no_packages++;
|
||||
|
||||
for (i = 0; i < no_packages ;i++) {
|
||||
for (i = 0; i < no_packages; i++) {
|
||||
if (remaining > (HCI_COMPLETE_FRAME))
|
||||
package_length = HCI_COMPLETE_FRAME;
|
||||
else
|
||||
@ -529,7 +531,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
|
||||
if (port->open_count) {
|
||||
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
|
||||
usb_rcvbulkpipe(port->serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
port->bulk_in_endpointAddress),
|
||||
port->read_urb->transfer_buffer,
|
||||
port->read_urb->transfer_buffer_length,
|
||||
aircable_read_bulk_callback, port);
|
||||
@ -602,7 +604,7 @@ static struct usb_serial_driver aircable_device = {
|
||||
.unthrottle = aircable_unthrottle,
|
||||
};
|
||||
|
||||
static int __init aircable_init (void)
|
||||
static int __init aircable_init(void)
|
||||
{
|
||||
int retval;
|
||||
retval = usb_serial_register(&aircable_device);
|
||||
@ -619,7 +621,7 @@ failed_usb_register:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit aircable_exit (void)
|
||||
static void __exit aircable_exit(void)
|
||||
{
|
||||
usb_deregister(&aircable_driver);
|
||||
usb_serial_deregister(&aircable_device);
|
||||
|
@ -68,8 +68,9 @@ static int airprime_send_setup(struct usb_serial_port *port)
|
||||
val |= 0x02;
|
||||
|
||||
return usb_control_msg(serial->dev,
|
||||
usb_rcvctrlpipe(serial->dev, 0),
|
||||
0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
|
||||
usb_rcvctrlpipe(serial->dev, 0),
|
||||
0x22, 0x21, val, 0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -90,17 +91,19 @@ static void airprime_read_bulk_callback(struct urb *urb)
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
|
||||
usb_serial_debug_data(debug, &port->dev, __func__,
|
||||
urb->actual_length, data);
|
||||
|
||||
tty = port->tty;
|
||||
if (tty && urb->actual_length) {
|
||||
tty_insert_flip_string (tty, data, urb->actual_length);
|
||||
tty_flip_buffer_push (tty);
|
||||
tty_insert_flip_string(tty, data, urb->actual_length);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
|
||||
result = usb_submit_urb (urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
|
||||
dev_err(&port->dev,
|
||||
"%s - failed resubmitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
return;
|
||||
}
|
||||
@ -115,7 +118,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
/* free up the transfer buffer, as usb_free_urb() does not do this */
|
||||
kfree (urb->transfer_buffer);
|
||||
kfree(urb->transfer_buffer);
|
||||
|
||||
if (status)
|
||||
dbg("%s - nonzero write bulk status received: %d",
|
||||
@ -171,7 +174,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
|
||||
}
|
||||
usb_fill_bulk_urb(urb, serial->dev,
|
||||
usb_rcvbulkpipe(serial->dev,
|
||||
port->bulk_out_endpointAddress),
|
||||
port->bulk_out_endpointAddress),
|
||||
buffer, buffer_size,
|
||||
airprime_read_bulk_callback, port);
|
||||
result = usb_submit_urb(urb, GFP_KERNEL);
|
||||
@ -183,7 +186,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
|
||||
__func__, i, port->number, result);
|
||||
goto errout;
|
||||
}
|
||||
/* remember this urb so we can kill it when the port is closed */
|
||||
/* remember this urb so we can kill it when the
|
||||
port is closed */
|
||||
priv->read_urbp[i] = urb;
|
||||
}
|
||||
|
||||
@ -192,22 +196,22 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
|
||||
goto out;
|
||||
|
||||
errout:
|
||||
/* some error happened, cancel any submitted urbs and clean up anything that
|
||||
got allocated successfully */
|
||||
/* some error happened, cancel any submitted urbs and clean up
|
||||
anything that got allocated successfully */
|
||||
|
||||
while (i-- != 0) {
|
||||
urb = priv->read_urbp[i];
|
||||
buffer = urb->transfer_buffer;
|
||||
usb_kill_urb (urb);
|
||||
usb_free_urb (urb);
|
||||
kfree (buffer);
|
||||
usb_kill_urb(urb);
|
||||
usb_free_urb(urb);
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void airprime_close(struct usb_serial_port *port, struct file * filp)
|
||||
static void airprime_close(struct usb_serial_port *port, struct file *filp)
|
||||
{
|
||||
struct airprime_private *priv = usb_get_serial_port_data(port);
|
||||
int i;
|
||||
@ -220,16 +224,16 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
|
||||
mutex_lock(&port->serial->disc_mutex);
|
||||
if (!port->serial->disconnected)
|
||||
airprime_send_setup(port);
|
||||
mutex_lock(&port->serial->disc_mutex);
|
||||
mutex_unlock(&port->serial->disc_mutex);
|
||||
|
||||
for (i = 0; i < NUM_READ_URBS; ++i) {
|
||||
usb_kill_urb (priv->read_urbp[i]);
|
||||
kfree (priv->read_urbp[i]->transfer_buffer);
|
||||
usb_free_urb (priv->read_urbp[i]);
|
||||
usb_kill_urb(priv->read_urbp[i]);
|
||||
kfree(priv->read_urbp[i]->transfer_buffer);
|
||||
usb_free_urb(priv->read_urbp[i]);
|
||||
}
|
||||
|
||||
/* free up private structure */
|
||||
kfree (priv);
|
||||
kfree(priv);
|
||||
usb_set_serial_port_data(port, NULL);
|
||||
}
|
||||
|
||||
@ -259,10 +263,10 @@ static int airprime_write(struct usb_serial_port *port,
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
dev_err(&port->dev, "no more free urbs\n");
|
||||
kfree (buffer);
|
||||
kfree(buffer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy (buffer, buf, count);
|
||||
memcpy(buffer, buf, count);
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
|
||||
|
||||
@ -279,7 +283,7 @@ static int airprime_write(struct usb_serial_port *port,
|
||||
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
|
||||
__func__, status);
|
||||
count = status;
|
||||
kfree (buffer);
|
||||
kfree(buffer);
|
||||
} else {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
++priv->outstanding_urbs;
|
||||
@ -287,7 +291,7 @@ static int airprime_write(struct usb_serial_port *port,
|
||||
}
|
||||
/* we are done with this urb, so let the host driver
|
||||
* really free it when it is finished with it */
|
||||
usb_free_urb (urb);
|
||||
usb_free_urb(urb);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -315,8 +319,10 @@ static int __init airprime_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
airprime_device.num_ports =
|
||||
(endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
|
||||
airprime_device.num_ports = endpoints;
|
||||
if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
|
||||
airprime_device.num_ports = NUM_BULK_EPS;
|
||||
|
||||
retval = usb_serial_register(&airprime_device);
|
||||
if (retval)
|
||||
return retval;
|
||||
@ -341,6 +347,7 @@ MODULE_LICENSE("GPL");
|
||||
module_param(debug, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Debug enabled");
|
||||
module_param(buffer_size, int, 0);
|
||||
MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
|
||||
MODULE_PARM_DESC(buffer_size,
|
||||
"Size of the transfer buffers in bytes (default 4096)");
|
||||
module_param(endpoints, int, 0);
|
||||
MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/serial.h>
|
||||
#include <linux/serial.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
||||
static int debug;
|
||||
@ -246,29 +246,29 @@ static void ark3116_set_termios(struct usb_serial_port *port,
|
||||
baud = tty_get_baud_rate(port->tty);
|
||||
|
||||
switch (baud) {
|
||||
case 75:
|
||||
case 150:
|
||||
case 300:
|
||||
case 600:
|
||||
case 1200:
|
||||
case 1800:
|
||||
case 2400:
|
||||
case 4800:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
case 230400:
|
||||
case 460800:
|
||||
/* Report the resulting rate back to the caller */
|
||||
tty_encode_baud_rate(port->tty, baud, baud);
|
||||
break;
|
||||
/* set 9600 as default (if given baudrate is invalid for example) */
|
||||
default:
|
||||
tty_encode_baud_rate(port->tty, 9600, 9600);
|
||||
case 0:
|
||||
baud = 9600;
|
||||
case 75:
|
||||
case 150:
|
||||
case 300:
|
||||
case 600:
|
||||
case 1200:
|
||||
case 1800:
|
||||
case 2400:
|
||||
case 4800:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
case 230400:
|
||||
case 460800:
|
||||
/* Report the resulting rate back to the caller */
|
||||
tty_encode_baud_rate(port->tty, baud, baud);
|
||||
break;
|
||||
/* set 9600 as default (if given baudrate is invalid for example) */
|
||||
default:
|
||||
tty_encode_baud_rate(port->tty, 9600, 9600);
|
||||
case 0:
|
||||
baud = 9600;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -380,19 +380,19 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
|
||||
switch (cmd) {
|
||||
case TIOCGSERIAL:
|
||||
/* XXX: Some of these values are probably wrong. */
|
||||
memset(&serstruct, 0, sizeof (serstruct));
|
||||
memset(&serstruct, 0, sizeof(serstruct));
|
||||
serstruct.type = PORT_16654;
|
||||
serstruct.line = port->serial->minor;
|
||||
serstruct.port = port->number;
|
||||
serstruct.custom_divisor = 0;
|
||||
serstruct.baud_base = 460800;
|
||||
|
||||
if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
|
||||
if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
case TIOCSSERIAL:
|
||||
if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
|
||||
if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
default:
|
||||
|
@ -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;
|
||||
|
@ -123,7 +123,8 @@ config USB_STORAGE_ALAUDA
|
||||
|
||||
config USB_STORAGE_ONETOUCH
|
||||
bool "Support OneTouch Button on Maxtor Hard Drives"
|
||||
depends on USB_STORAGE && INPUT_EVDEV
|
||||
depends on USB_STORAGE
|
||||
depends on INPUT=y || INPUT=USB_STORAGE
|
||||
help
|
||||
Say Y here to include additional code to support the Maxtor OneTouch
|
||||
USB hard drive's onetouch button.
|
||||
|
@ -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: "
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include "onetouch.h"
|
||||
#include "debug.h"
|
||||
|
||||
void onetouch_release_input(void *onetouch_);
|
||||
static void onetouch_release_input(void *onetouch_);
|
||||
|
||||
struct usb_onetouch {
|
||||
char name[128];
|
||||
@ -223,7 +223,7 @@ int onetouch_connect_input(struct us_data *ss)
|
||||
return error;
|
||||
}
|
||||
|
||||
void onetouch_release_input(void *onetouch_)
|
||||
static void onetouch_release_input(void *onetouch_)
|
||||
{
|
||||
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
|
||||
|
||||
|
@ -44,7 +44,8 @@
|
||||
* running with this patch.
|
||||
* Send your submission to either Phil Dibowitz <phil@ipom.com> or
|
||||
* Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
|
||||
* USB development list <linux-usb-devel@lists.sourceforge.net>.
|
||||
* USB development list <linux-usb@vger.kernel.org> and the USB storage list
|
||||
* <usb-storage@lists.one-eyed-alien.net>
|
||||
*/
|
||||
|
||||
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
|
||||
@ -557,6 +558,13 @@ UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
|
||||
US_FL_SINGLE_LUN),
|
||||
#endif
|
||||
|
||||
/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
|
||||
UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
|
||||
"Samsung",
|
||||
"YP-U3",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_MAX_SECTORS_64),
|
||||
|
||||
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
|
||||
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
|
||||
"Belkin",
|
||||
@ -1200,6 +1208,17 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110,
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_BULK32),
|
||||
|
||||
/* Andrew Lunn <andrew@lunn.ch>
|
||||
* PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
|
||||
* on LUN 4.
|
||||
* Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
|
||||
*/
|
||||
UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
|
||||
"PanDigital",
|
||||
"Photo Frame",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_NOT_LOCKABLE),
|
||||
|
||||
/* Submitted by Jan De Luyck <lkml@kcore.org> */
|
||||
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
|
||||
"CITIZEN",
|
||||
@ -1342,6 +1361,13 @@ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_FIX_INQUIRY),
|
||||
|
||||
/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
|
||||
UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
|
||||
"INTOVA",
|
||||
"Pixtreme",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_FIX_CAPACITY ),
|
||||
|
||||
/*
|
||||
* Entry for Jenoptik JD 5200z3
|
||||
*
|
||||
|
@ -539,7 +539,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
|
||||
" has %s in unusual_devs.h (kernel"
|
||||
" %s)\n"
|
||||
" Please send a copy of this message to "
|
||||
"<linux-usb-devel@lists.sourceforge.net>\n",
|
||||
"<linux-usb@vger.kernel.org> and "
|
||||
"<usb-storage@lists.one-eyed-alien.net>\n",
|
||||
le16_to_cpu(ddesc->idVendor),
|
||||
le16_to_cpu(ddesc->idProduct),
|
||||
le16_to_cpu(ddesc->bcdDevice),
|
||||
|
48
include/linux/usb/c67x00.h
Normal file
48
include/linux/usb/c67x00.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip
|
||||
*
|
||||
* Copyright (C) 2006-2008 Barco N.V.
|
||||
*
|
||||
* 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 _LINUX_USB_C67X00_H
|
||||
#define _LINUX_USB_C67X00_H
|
||||
|
||||
/* SIE configuration */
|
||||
#define C67X00_SIE_UNUSED 0
|
||||
#define C67X00_SIE_HOST 1
|
||||
#define C67X00_SIE_PERIPHERAL_A 2 /* peripheral on A port */
|
||||
#define C67X00_SIE_PERIPHERAL_B 3 /* peripheral on B port */
|
||||
|
||||
#define c67x00_sie_config(config, n) (((config)>>(4*(n)))&0x3)
|
||||
|
||||
#define C67X00_SIE1_UNUSED (C67X00_SIE_UNUSED << 0)
|
||||
#define C67X00_SIE1_HOST (C67X00_SIE_HOST << 0)
|
||||
#define C67X00_SIE1_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 0)
|
||||
#define C67X00_SIE1_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 0)
|
||||
|
||||
#define C67X00_SIE2_UNUSED (C67X00_SIE_UNUSED << 4)
|
||||
#define C67X00_SIE2_HOST (C67X00_SIE_HOST << 4)
|
||||
#define C67X00_SIE2_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 4)
|
||||
#define C67X00_SIE2_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 4)
|
||||
|
||||
struct c67x00_platform_data {
|
||||
int sie_config; /* SIEs config (C67X00_SIEx_*) */
|
||||
unsigned long hpi_regstep; /* Step between HPI registers */
|
||||
};
|
||||
|
||||
#endif /* _LINUX_USB_C67X00_H */
|
@ -455,7 +455,7 @@ struct usb_encryption_descriptor {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* USB_DT_BOS: group of wireless capabilities */
|
||||
/* USB_DT_BOS: group of device-level capabilities */
|
||||
struct usb_bos_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
@ -501,6 +501,16 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
|
||||
__u8 bReserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define USB_CAP_TYPE_EXT 2
|
||||
|
||||
struct usb_ext_cap_descriptor { /* Link Power Management */
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDevCapabilityType;
|
||||
__u8 bmAttributes;
|
||||
#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
|
||||
|
@ -114,6 +114,8 @@ struct usb_ep_ops {
|
||||
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
|
||||
|
||||
int (*set_halt) (struct usb_ep *ep, int value);
|
||||
int (*set_wedge) (struct usb_ep *ep);
|
||||
|
||||
int (*fifo_status) (struct usb_ep *ep);
|
||||
void (*fifo_flush) (struct usb_ep *ep);
|
||||
};
|
||||
@ -348,6 +350,25 @@ static inline int usb_ep_clear_halt(struct usb_ep *ep)
|
||||
return ep->ops->set_halt(ep, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_ep_set_wedge - sets the halt feature and ignores clear requests
|
||||
* @ep: the endpoint being wedged
|
||||
*
|
||||
* Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
|
||||
* requests. If the gadget driver clears the halt status, it will
|
||||
* automatically unwedge the endpoint.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
static inline int
|
||||
usb_ep_set_wedge(struct usb_ep *ep)
|
||||
{
|
||||
if (ep->ops->set_wedge)
|
||||
return ep->ops->set_wedge(ep);
|
||||
else
|
||||
return ep->ops->set_halt(ep, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_ep_fifo_status - returns number of bytes in fifo, or error
|
||||
* @ep: the endpoint whose fifo status is being checked.
|
||||
|
Loading…
x
Reference in New Issue
Block a user