📄 net2280.c
字号:
tmp = readl (&dev->usb->usbctl);
if (value)
tmp |= (1 << SELF_POWERED_STATUS);
else
tmp &= ~(1 << SELF_POWERED_STATUS);
writel (tmp, &dev->usb->usbctl);
spin_unlock_irqrestore (&dev->lock, flags);
return 0;
}
static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
{
struct net2280 *dev;
u32 tmp;
unsigned long flags;
if (!_gadget)
return -ENODEV;
dev = container_of (_gadget, struct net2280, gadget);
spin_lock_irqsave (&dev->lock, flags);
tmp = readl (&dev->usb->usbctl);
dev->softconnect = (is_on != 0);
if (is_on)
tmp |= (1 << USB_DETECT_ENABLE);
else
tmp &= ~(1 << USB_DETECT_ENABLE);
writel (tmp, &dev->usb->usbctl);
spin_unlock_irqrestore (&dev->lock, flags);
return 0;
}
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
.wakeup = net2280_wakeup,
.set_selfpowered = net2280_set_selfpowered,
.pullup = net2280_pullup,
};
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
/* FIXME move these into procfs, and use seq_file.
* Sysfs _still_ doesn't behave for arbitrarily sized files,
* and also doesn't help products using this with 2.4 kernels.
*/
/* "function" sysfs attribute */
static ssize_t
show_function (struct device *_dev, struct device_attribute *attr, char *buf)
{
struct net2280 *dev = dev_get_drvdata (_dev);
if (!dev->driver
|| !dev->driver->function
|| strlen (dev->driver->function) > PAGE_SIZE)
return 0;
return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
}
static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
static ssize_t
show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
{
struct net2280 *dev;
char *next;
unsigned size, t;
unsigned long flags;
int i;
u32 t1, t2;
const char *s;
dev = dev_get_drvdata (_dev);
next = buf;
size = PAGE_SIZE;
spin_lock_irqsave (&dev->lock, flags);
if (dev->driver)
s = dev->driver->driver.name;
else
s = "(none)";
/* Main Control Registers */
t = scnprintf (next, size, "%s version " DRIVER_VERSION
", chiprev %04x, dma %s\n\n"
"devinit %03x fifoctl %08x gadget '%s'\n"
"pci irqenb0 %02x irqenb1 %08x "
"irqstat0 %04x irqstat1 %08x\n",
driver_name, dev->chiprev,
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled",
readl (&dev->regs->devinit),
readl (&dev->regs->fifoctl),
s,
readl (&dev->regs->pciirqenb0),
readl (&dev->regs->pciirqenb1),
readl (&dev->regs->irqstat0),
readl (&dev->regs->irqstat1));
size -= t;
next += t;
/* USB Control Registers */
t1 = readl (&dev->usb->usbctl);
t2 = readl (&dev->usb->usbstat);
if (t1 & (1 << VBUS_PIN)) {
if (t2 & (1 << HIGH_SPEED))
s = "high speed";
else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
s = "powered";
else
s = "full speed";
/* full speed bit (6) not working?? */
} else
s = "not attached";
t = scnprintf (next, size,
"stdrsp %08x usbctl %08x usbstat %08x "
"addr 0x%02x (%s)\n",
readl (&dev->usb->stdrsp), t1, t2,
readl (&dev->usb->ouraddr), s);
size -= t;
next += t;
/* PCI Master Control Registers */
/* DMA Control Registers */
/* Configurable EP Control Registers */
for (i = 0; i < 7; i++) {
struct net2280_ep *ep;
ep = &dev->ep [i];
if (i && !ep->desc)
continue;
t1 = readl (&ep->regs->ep_cfg);
t2 = readl (&ep->regs->ep_rsp) & 0xff;
t = scnprintf (next, size,
"\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
"irqenb %02x\n",
ep->ep.name, t1, t2,
(t2 & (1 << CLEAR_NAK_OUT_PACKETS))
? "NAK " : "",
(t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE))
? "hide " : "",
(t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR))
? "CRC " : "",
(t2 & (1 << CLEAR_INTERRUPT_MODE))
? "interrupt " : "",
(t2 & (1<<CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE))
? "status " : "",
(t2 & (1 << CLEAR_NAK_OUT_PACKETS_MODE))
? "NAKmode " : "",
(t2 & (1 << CLEAR_ENDPOINT_TOGGLE))
? "DATA1 " : "DATA0 ",
(t2 & (1 << CLEAR_ENDPOINT_HALT))
? "HALT " : "",
readl (&ep->regs->ep_irqenb));
size -= t;
next += t;
t = scnprintf (next, size,
"\tstat %08x avail %04x "
"(ep%d%s-%s)%s\n",
readl (&ep->regs->ep_stat),
readl (&ep->regs->ep_avail),
t1 & 0x0f, DIR_STRING (t1),
type_string (t1 >> 8),
ep->stopped ? "*" : "");
size -= t;
next += t;
if (!ep->dma)
continue;
t = scnprintf (next, size,
" dma\tctl %08x stat %08x count %08x\n"
"\taddr %08x desc %08x\n",
readl (&ep->dma->dmactl),
readl (&ep->dma->dmastat),
readl (&ep->dma->dmacount),
readl (&ep->dma->dmaaddr),
readl (&ep->dma->dmadesc));
size -= t;
next += t;
}
/* Indexed Registers */
// none yet
/* Statistics */
t = scnprintf (next, size, "\nirqs: ");
size -= t;
next += t;
for (i = 0; i < 7; i++) {
struct net2280_ep *ep;
ep = &dev->ep [i];
if (i && !ep->irqs)
continue;
t = scnprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs);
size -= t;
next += t;
}
t = scnprintf (next, size, "\n");
size -= t;
next += t;
spin_unlock_irqrestore (&dev->lock, flags);
return PAGE_SIZE - size;
}
static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static ssize_t
show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
{
struct net2280 *dev;
char *next;
unsigned size;
unsigned long flags;
int i;
dev = dev_get_drvdata (_dev);
next = buf;
size = PAGE_SIZE;
spin_lock_irqsave (&dev->lock, flags);
for (i = 0; i < 7; i++) {
struct net2280_ep *ep = &dev->ep [i];
struct net2280_request *req;
int t;
if (i != 0) {
const struct usb_endpoint_descriptor *d;
d = ep->desc;
if (!d)
continue;
t = d->bEndpointAddress;
t = scnprintf (next, size,
"\n%s (ep%d%s-%s) max %04x %s fifo %d\n",
ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
(t & USB_DIR_IN) ? "in" : "out",
({ char *val;
switch (d->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
val = "bulk"; break;
case USB_ENDPOINT_XFER_INT:
val = "intr"; break;
default:
val = "iso"; break;
}; val; }),
le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
ep->dma ? "dma" : "pio", ep->fifo_size
);
} else /* ep0 should only have one transfer queued */
t = scnprintf (next, size, "ep0 max 64 pio %s\n",
ep->is_in ? "in" : "out");
if (t <= 0 || t > size)
goto done;
size -= t;
next += t;
if (list_empty (&ep->queue)) {
t = scnprintf (next, size, "\t(nothing queued)\n");
if (t <= 0 || t > size)
goto done;
size -= t;
next += t;
continue;
}
list_for_each_entry (req, &ep->queue, queue) {
if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc))
t = scnprintf (next, size,
"\treq %p len %d/%d "
"buf %p (dmacount %08x)\n",
&req->req, req->req.actual,
req->req.length, req->req.buf,
readl (&ep->dma->dmacount));
else
t = scnprintf (next, size,
"\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
if (t <= 0 || t > size)
goto done;
size -= t;
next += t;
if (ep->dma) {
struct net2280_dma *td;
td = req->td;
t = scnprintf (next, size, "\t td %08x "
" count %08x buf %08x desc %08x\n",
(u32) req->td_dma,
le32_to_cpu (td->dmacount),
le32_to_cpu (td->dmaaddr),
le32_to_cpu (td->dmadesc));
if (t <= 0 || t > size)
goto done;
size -= t;
next += t;
}
}
}
done:
spin_unlock_irqrestore (&dev->lock, flags);
return PAGE_SIZE - size;
}
static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
#else
#define device_create_file(a,b) do {} while (0)
#define device_remove_file device_create_file
#endif
/*-------------------------------------------------------------------------*/
/* another driver-specific mode might be a request type doing dma
* to/from another device fifo instead of to/from memory.
*/
static void set_fifo_mode (struct net2280 *dev, int mode)
{
/* keeping high bits preserves BAR2 */
writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl);
/* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */
INIT_LIST_HEAD (&dev->gadget.ep_list);
list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list);
list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list);
switch (mode) {
case 0:
list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list);
dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024;
break;
case 1:
dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048;
break;
case 2:
list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
dev->ep [1].fifo_size = 2048;
dev->ep [2].fifo_size = 1024;
break;
}
/* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */
list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list);
list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
}
/* just declare this in any driver that really need it */
extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
/**
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
* @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
* 1 for two 2kB buffers (ep-a and ep-b only);
* 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
*
* returns zero on success, else negative errno. when this succeeds,
* the contents of gadget->ep_list may have changed.
*
* you may only call this function when endpoints a-d are all disabled.
* use it whenever extra hardware buffering can help performance, such
* as before enabling "high bandwidth" interrupt endpoints that use
* maxpacket bigger than 512 (when double buffering would otherwise
* be unavailable).
*/
int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
{
int i;
struct net2280 *dev;
int status = 0;
unsigned long flags;
if (!gadget)
return -ENODEV;
dev = container_of (gadget, struct net2280, gadget);
spin_lock_irqsave (&dev->lock, flags);
for (i = 1; i <= 4; i++)
if (dev->ep [i].desc) {
status = -EINVAL;
break;
}
if (mode < 0 || mode > 2)
status = -EINVAL;
if (status == 0)
set_fifo_mode (dev, mode);
spin_unlock_irqrestore (&dev->lock, flags);
if (status == 0) {
if (mode == 1)
DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n");
else if (mode == 2)
DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n");
/* else all are 1K */
}
return status;
}
EXPORT_SYMBOL (net2280_set_fifo_mode);
/*-------------------------------------------------------------------------*/
/* keeping it simple:
* - one bus driver, initted first;
* - one function driver, initted second
*
* most of the work to support multiple net2280 controllers would
* be to associate this gadget driver (yes?) with all of them, or
* perhaps to bind specific drivers to specific devices.
*/
static struct net2280 *the_controller;
static void usb_reset (struct net2280 *dev)
{
u32 tmp;
dev->gadget.speed = USB_SPEED_UNKNOWN;
(void) readl (&dev->usb->usbctl);
net2280_led_init (dev);
/* disable automatic responses, and irqs */
writel (0, &dev->usb->stdrsp);
writel (0, &dev->regs->pciirqenb0);
writel (0, &dev->regs->pciirqenb1);
/* clear old dma and irq state */
for (tmp = 0; tmp < 4; tmp++) {
struct net2280_ep *ep = &dev->ep [tmp + 1];
if (ep->dma)
abort_dma (ep);
}
writel (~0, &dev->regs->irqstat0),
writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1),
/* reset, and enable pci */
tmp = readl (&dev->regs->devinit)
| (1 << PCI_ENABLE)
| (1 << FIFO_SOFT_RESET)
| (1 << USB_SOFT_RESET)
| (1 << M8051_RESET);
writel (tmp, &dev->regs->devinit);
/* standard fifo and endpoint allocations */
set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0);
}
static void usb_reinit (struct net2280 *dev)
{
u32 tmp;
int init_dma;
/* use_dma changes are ignored till next device re-init */
init_dma = use_dma;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -