Hi,
>> Here are the last two setup data and CBW data received. the
>> get_next_command() is not called when CBW data is received. the
>> bulk_out_complete() wakes up the thread, however, get_next_command()
>> still sleeps. i do not see where req->length is checked in gadget
>> driver.
>>
>> g_file_storage gadget: ep0-setup, length 8:
>> 00000000: 00 09 01 00 00 00 00 00
>> g_file_storage gadget: set configuration
>> g_file_storage gadget: ep0-setup, length 8:
>> 00000000: a1 fe 00 00 00 00 01 00
>> g_file_storage gadget: get max LUN
>> g_file_storage gadget: ep0-in, length 1:
>> 00000000: 00
>> g_file_storage gadget: bulk-out, length 31:
>> 00000000: 55 53 42 43 a8 48 ed 86 24 00 00 00 80 00 06 12
>> 00000010: 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00
>> g_file_storage gadget: bulk_out_complete --> 0, 31/0
>
> file_storage uses bulk_out_intended_length.
>
> You're on your own, to be fair, using a really old kernel, you never
> posted your UDC driver for review, so you need to fix it all up by
> yourself.
>
> Read the code, add prints, look at other UDC drivers. g_file_storage is
> next to perfect and proven to work with many, many different setups.
Here is my UDC driver code. I use a kthread to poll the hardware
register EP0 and EP1 interrupt. I removed the HW register access code.
If it is required, i can send the full code. Something could be wrong
in my UDC driver. Thanks.
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#define NUM_ENDPOINTS 3
#define EP_MAX_PACKET_SIZE 0x200
#define EP0_MAX_PACKET_SIZE 64
#define QH_MAXNUM 32
/*-------------------------------------------------------------*/
#define IO_OFFSET 0x55000000
#define __IO_ADDRESS(x) ((x) + IO_OFFSET)
#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
#ifdef IOMEM // Override asm/io.h
#undef IOMEM
#endif // IOMEM
#ifdef __ASSEMBLER__
#define IOMEM(x) x
#else
#define IOMEM(x) ((void __force __iomem *)(x))
#endif
#define ka2000_readb(a) __raw_readb(IO_ADDRESS(a))
#define ka2000_readw(a) __raw_readw(IO_ADDRESS(a))
#define ka2000_readl(a) __raw_readl(IO_ADDRESS(a))
#define ka2000_writeb(v, a) __raw_writeb(v, IO_ADDRESS(a))
#define ka2000_writew(v, a) __raw_writew(v, IO_ADDRESS(a))
#define ka2000_writel(v, a) __raw_writel(v, IO_ADDRESS(a))
/*-------------------------------------------------------------*/
static const char *reqname(unsigned r)
{
switch (r) {
case USB_REQ_GET_STATUS: return "GET_STATUS";
case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
case USB_REQ_SET_FEATURE: return "SET_FEATURE";
case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
default: return "*UNKNOWN*";
}
}
static struct usb_endpoint_descriptor ep0_out_desc = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
};
static struct usb_endpoint_descriptor ep0_in_desc = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
};
struct kagen2;
struct kagen2_request {
struct usb_request req;
struct list_head queue;
unsigned mapped:1,
valid:1;
};
struct ka_ep {
struct usb_ep ep;
struct kagen2 * dev;
unsigned long irqs;
struct usb_request req;
struct list_head queue;
const struct usb_endpoint_descriptor *desc;
unsigned num:8,
fifo_size:12,
stopped:1,
wedged:1,
is_in:1,
is_iso:1,
dma:1,
not_empty:1;
};
struct ka_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
};
#define CONFIG_MAX_PKT(n) ((n) << 16)
#define TERMINATE 1
#define INFO_BYTES(n) ((n) << 16)
#define INFO_IOC (1 << 15)
#define INFO_ACTIVE (1 << 7)
#define INFO_HALTED (1 << 6)
#define INFO_BUFFER_ERROR (1 << 5)
#define INFO_TX_ERROR (1 << 3)
static struct ka_ep ka_ep_g[NUM_ENDPOINTS];
enum SPEED {
LOWSPEED = 0,
FULLSPEED = 1,
HIGHSPEED = 2,
};
enum STATE {
DEFAULT = 0,
SUSPENDED
};
int system_level = 0;
unsigned char device_state = 0;
unsigned char device_speed = FULLSPEED;
static void handle_ep_complete(struct ka_ep *ka_ep_p, struct
kagen2_request *req)
{
int num, in;
printk("%s %x\n",__func__, ka_ep_p->desc);
num = ka_ep_p->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ka_ep_p->desc->bEndpointAddress & USB_DIR_IN) != 0;
if (num == 0)
ka_ep_p->desc = &ep0_out_desc;
//ep->req.length -= len;
printk("ept%d %s complete %x\n",
num, in ? "in" : "out", ka_ep_p->req.length);
// call gadget code
ka_ep_p->req.complete(&ka_ep_p->ep, &req->req);
if (num == 0) {
ka_ep_p->req.length = 0;
usb_ep_queue(&ka_ep_p->ep, &req->req, 0);
ka_ep_p->desc = &ep0_in_desc;
}
}
/*--------------------------------------------------------------------------*/
static int kagen2_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
static int kagen2_ep_disable(struct usb_ep *ep);
static int kagen2_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags);
static int kagen2_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req);
static struct usb_request *
kagen2_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
static void kagen2_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
static int
kagen2_get_frame(struct usb_gadget *_gadget);
static int
kagen2_wakeup(struct usb_gadget *_gadget);
static int
kagen2_set_selfpowered(struct usb_gadget *_gadget, int value);
static int
kagen2_pullup(struct usb_gadget *_gadget, int is_on);
static int
kagen2_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
static int
kagen2_stop(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
#define DRIVER_DESC "KAgen2 USB Peripheral Controller"
static const char driver_name[] = "kagen2_usb";
static const char driver_vers[] = "2012 december";
static const char driver_desc[] = DRIVER_DESC;
static const char ep0name[] = "ep0";
static const char * const ep_name[] = {
ep0name,
"ep1", "ep1",
};
struct kagen2 {
/* each device provides one gadget, several endpoints */
struct usb_gadget gadget;
struct device *dev;
unsigned short dev_id;
spinlock_t lock;
struct ka_ep ep[NUM_ENDPOINTS];
struct usb_gadget_driver *driver;
unsigned protocol_stall:1,
softconnect:1,
is_selfpowered:1,
wakeup:1,
dma_eot_polarity:1,
dma_dack_polarity:1,
dma_dreq_polarity:1,
dma_busy:1;
u16 chiprev;
u8 pagesel;
unsigned int irq;
unsigned short fifo_mode;
void __iomem *base_addr;
};
#define SETUP(type, request) (((type) << 8) | (request))
static void handle_setup(struct kagen2 * dev, int bmRequestType, int
bRequest, int wValue, int wIndex, int wLength)
{
struct usb_request *req = &(dev->ep[0].req);
struct usb_ctrlrequest r;
int status = 0;
int num, in, _num, _in, i;
char *buf;
if (wLength == 0 && wValue == 0)
return;
r.bRequestType = bmRequestType;
r.bRequest = bRequest;
r.wValue = wValue;
r.wIndex = wIndex;
r.wLength = wLength;
printk("handle setup %s, %x, %x index %x value %x len %x\n",
reqname(r.bRequest),
r.bRequestType, r.bRequest, r.wIndex, r.wValue, r.wLength);
switch (SETUP(r.bRequestType, r.bRequest)) {
case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
printk("USB_RECIP_ENDPOINT\n");
_num = r.wIndex & 15;
_in = !!(r.wIndex & 0x80);
if ((r.wValue == 0) && (r.wLength == 0)) {
req->length = 0;
for (i = 0; i < NUM_ENDPOINTS; i++) {
if (!dev->ep[i].desc)
continue;
num = dev->ep[i].desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (dev->ep[i].desc->bEndpointAddress
& USB_DIR_IN) != 0;
if ((num == _num) && (in == _in)) {
//ep_enable(num, in);
usb_ep_queue(dev->gadget.ep0,
req, 0);
break;
}
}
}
return;
case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
/*
* write address delayed (will take effect
* after the next IN txn)
*/
printk("USB_RECIP_DEVICE\n");
req->length = 0;
usb_ep_queue(dev->gadget.ep0, req, 0);
return;
case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
printk("USB_REQ_GET_STATUS\n");
req->length = 2;
buf = (char *)req->buf;
buf[0] = 1 << USB_DEVICE_SELF_POWERED;
buf[1] = 0;
usb_ep_queue(dev->gadget.ep0, req, 0);
return;
}
/* pass request up to the gadget driver */
if (!dev->driver)
{
printk("driver not defined\n");
return;
}
if (!dev->driver->setup)
{
printk("setup not defined\n");
return;
}
status = dev->driver->setup(&dev->gadget, &r);
printk("status %d\n", status);
return;
}
static void ep1_out(struct kagen2 * dev)
{
unsigned int val_arr[16];
int len;
int i, in, num;
unsigned int val;
//EP1 OUT IRQ
// get byte cnt
val = readl(dev->base_addr + 0x008);
len = val & 0xFF;
// read from fifo1 data
for (i = 0; i < len/4; i++)
{
val_arr[i] = readl(dev->base_addr + 0x084);
printk("0x%x ",val_arr[i]);
}
if ((len%4) != 0)
{
val_arr[i] = readl(dev->base_addr + 0x084);
}
//bulk out ep
if (dev->ep[2].desc) {
struct kagen2_request * ka_req;
struct usb_request * req;
if (list_empty(&dev->ep[2].queue)) {
printk(
"%s: RX DMA done : NULL REQ on OUT EP-1\n",
__func__);
//return;
}
//req = list_entry(dev->ep[2].queue.next, struct
kagen2_request, queue);
req = &dev->ep[2].req;
ka_req = container_of(req, struct kagen2_request, req);
if (ka_req == NULL)
{
printk("req NULL\n");
return;
}
//ka_req->req.length = len;
ka_req->req.actual = len;
memcpy(ka_req->req.buf, &val_arr[0], len);
num = dev->ep[2].desc->bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
in = (dev->ep[2].desc->bEndpointAddress
& USB_DIR_IN) != 0;
printk("epnum %d in %d\n", num, in);
printk("len %d\n", len);
handle_ep_complete(&dev->ep[2], ka_req);
}
}
static irqreturn_t kagen2_irq(int irq, void * _dev)
{
unsigned int val;
int i, in, num;
struct kagen2 *dev = _dev;
return IRQ_HANDLED;
}
static void kagen2_lowlevel_init(struct kagen2 * dev)
{
// initialize the hardware
}
static struct usb_ep_ops kagen2_ep_ops = {
.enable = kagen2_ep_enable,
.disable = kagen2_ep_disable,
.alloc_request = kagen2_ep_alloc_request,
.free_request = kagen2_ep_free_request,
.queue = kagen2_ep_queue,
.dequeue = kagen2_ep_dequeue,
};
static struct usb_gadget_ops kagen2_gadget_ops = {
.get_frame = kagen2_get_frame,
.wakeup = kagen2_wakeup,
.set_selfpowered = kagen2_set_selfpowered,
.pullup = kagen2_pullup,
.udc_start = kagen2_start,
.udc_stop = kagen2_stop,
};
static int
kagen2_get_frame(struct usb_gadget *_gadget)
{
struct kagen2 *dev;
unsigned long flags;
u16 ret;
if (!_gadget)
return -ENODEV;
dev = container_of(_gadget, struct kagen2, gadget);
spin_lock_irqsave(&dev->lock, flags);
spin_unlock_irqrestore(&dev->lock, flags);
return ret;
}
static int
kagen2_wakeup(struct usb_gadget *_gadget)
{
struct kagen2 *dev;
unsigned long flags;
if (!_gadget)
return 0;
dev = container_of(_gadget, struct kagen2, gadget);
spin_lock_irqsave(&dev->lock, flags);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
static int
kagen2_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct kagen2 *dev;
if (!_gadget)
return -ENODEV;
dev = container_of(_gadget, struct kagen2, gadget);
dev->is_selfpowered = value;
return 0;
}
static int
kagen2_pullup(struct usb_gadget *_gadget, int is_on)
{
struct kagen2 *dev;
unsigned long flags;
if (!_gadget)
return -ENODEV;
dev = container_of(_gadget, struct kagen2, gadget);
spin_lock_irqsave(&dev->lock, flags);
dev->softconnect = (is_on != 0);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
static int kagen2_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver)
{
struct kagen2 *dev;
unsigned i;
struct ka_ep *ka_ep;
printk("0x%x 0x%x\n", driver, driver->setup);
//if (!driver || !driver->unbind || !driver->setup ||
// driver->max_speed != USB_SPEED_HIGH)
if (!driver)
return -EINVAL;
dev = container_of(_gadget, struct kagen2, gadget);
printk("%s\n", __func__);
printk("0x%x 0x%x\n", driver, driver->setup);
for (i = 0; i < 4; ++i)
dev->ep[i].irqs = 0;
/* hook up the driver ... */
dev->softconnect = 1;
driver->driver.bus = NULL;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
dev->gadget.speed = USB_SPEED_HIGH;
//kagen2_ep0_start();
ka_ep = &dev->ep[0];
printk("0x%x 0x%x\n", &ka_ep->ep, &ep0_in_desc);
kagen2_ep_enable(&ka_ep->ep, &ep0_in_desc);
//ka_ep = &dev->ep[1];
//kagen2_ep_enable(&ka_ep->ep, &ep0_out_desc);
return 0;
}
static int kagen2_stop(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver)
{
struct kagen2 *dev;
unsigned long flags;
dev = container_of(_gadget, struct kagen2, gadget);
spin_lock_irqsave(&dev->lock, flags);
spin_unlock_irqrestore(&dev->lock, flags);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
return 0;
}
static int kagen2_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct ka_ep *ka_ep = container_of(ep, struct ka_ep, ep);
int num, in;
num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
ka_ep->desc = desc;
printk("%s %d %d\n",__func__, num, in);
printk("%x %x %x \n", ep, desc, ka_ep);
return 0;
}
static int kagen2_ep_disable(struct usb_ep *ep)
{
return 0;
}
static struct usb_request *
kagen2_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
{
struct ka_ep *ka_ep = container_of(ep, struct ka_ep, ep);
return &ka_ep->req;
}
static void kagen2_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
{
return;
}
static void ep0_in(unsigned int phys, int len, struct kagen2 * dev)
{
unsigned int val32;
unsigned int iter_num = 0;
int i;
// send to EP0 IN buffer
return;
}
static void ep1_in(unsigned int phys, int len, struct kagen2 * dev)
{
unsigned int iter_num = 0, len_num = 0;
unsigned int val32;
int i;
int num = 1;
// send to EP1 IN buffer
return;
}
static int kagen2_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
{
struct ka_ep *ka_ep;
struct kagen2_request *ka_req;
struct kagen2 * dev;
unsigned phys;
int num, len, in;
printk("%s\n",__func__);
ka_req = container_of(req, struct kagen2_request, req);
if (!req || !req->complete || !req->buf
|| !list_empty(&ka_req->queue))
return -EINVAL;
ka_ep = container_of(ep, struct ka_ep, ep);
if (!ep || (!ka_ep->desc && ka_ep->num != 0))
return -EINVAL;
printk("%s %x %x\n",__func__, ka_ep, ka_ep->desc);
dev = ka_ep->dev;
//printk("0x%x 0x%x 0x%x 0x%x\n", dev, dev->driver, ka_ep, ka_req);
if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
num = ka_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ka_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
phys = (unsigned)req->buf;
len = req->length;
printk("ept%d %s queue len 0x%x, buffer 0x%x\n",
num, in ? "in" : "out", len, phys);
if ((len > 0) && (num == 0) && (in != 0))
{
req->actual = 0;
ep0_in(phys, len, dev);
req->actual += len;
req->complete(ep, req);
return 0;
}
else if ((len > 0) && (num == 1) && (in != 0))
{
ep1_in(phys, len, dev);
return len;
}
else if (in == 0)
{
// read from EPxOUT buffer
if (num == 1)
{
//struct usb_request * temp = &(ka_ep->req);
printk("EP1 %x\n", (u8 *)ka_ep) ;
list_add_tail(&ka_req->queue, &ka_ep->queue);
}
}
return 0;
}
static int
kagen2_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct ka_ep *ep;
struct kagen2_request *req;
unsigned long flags;
ep = container_of(_ep, struct ka_ep, ep);
spin_lock_irqsave(&ep->dev->lock, flags);
/* make sure it's still queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req)
break;
}
if (&req->req != _req) {
spin_unlock_irqrestore(&ep->dev->lock, flags);
return -EINVAL;
}
req = NULL;
spin_unlock_irqrestore(&ep->dev->lock, flags);
return 0;
}
static void
kagen2_gadget_release(struct device *_dev)
{
struct kagen2 *dev = dev_get_drvdata(_dev);
kfree(dev);
}
// for kernel thread
struct task_struct * task;
static int example_thread(void * data)
{
int i = 0;
volatile unsigned int val;
struct kagen2 * dev = (struct kagen2 *)data;
for (;;)
{
{
i = 0;
val = readl(dev->base_addr + 0x1a0);
val = val & 0xff;
//printk("INTC IVECT %x\n", val);
if (val == 0xd8)
{
//peripirq
val = readl(dev->base_addr + 0x1bc);
val &= 0xffffff00;
val |= 0x00000011;
writel(val, dev->base_addr + 0x1bc);
}
else if (val == 0x00)
{
int bmRequestType;
int bRequest;
unsigned int wLength, wValue, wIndex;
unsigned int rdata, rdata1;
// setup data valid
val = readl(dev->base_addr + 0x18c);
val &= 0xffffff00;
val |= 0x00000001;
writel(val, dev->base_addr + 0x18c);
// process the setup data
rdata = readl(dev->base_addr + 0x180) ;
rdata1 = readl(dev->base_addr + 0x184);
bmRequestType = rdata & 0xff;
bRequest = (rdata >> 8) & 0xff;
wValue = (rdata >> 16) & 0xffff;
wIndex = rdata1 & 0xffff;
wLength = (rdata1 >> 16) & 0xffff;
handle_setup(dev, bmRequestType, bRequest, wValue,
wIndex, wLength);
}
else if (val == 0x28)
{
printk("EPx OUT IRQ 0x%x\n", val);
ep1_out(dev);
}
}
}
return 0;
}
// end for kernel thread
static int __devinit
kagen2_plat_probe(struct platform_device *pdev)
{
struct kagen2 *dev;
int ret; int i;
unsigned int irqflags;
resource_size_t base, len;
struct resource *iomem, *irq_res;
printk("kagen2_plat_probe 1\n");
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!irq_res || !iomem) {
printk("kagen2_plat_probe 2\n");
return -EINVAL;
}
if (!irq_res->start) {
printk("kagen2_plat_probe 3\n");
return (-ENODEV);
}
/* alloc, and start init */
dev = kzalloc(sizeof(struct kagen2), GFP_KERNEL);
if (!dev)
{
printk("kagen2_plat_probe 4\n");
return (-ENOMEM);
}
printk("kagen2_plat_probe 5\n");
spin_lock_init(&dev->lock);
dev->irq = irq_res->start;
dev->dev = &(pdev->dev);
dev->gadget.ops = &kagen2_gadget_ops;
dev->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.dev.parent = &(pdev->dev);
dev->gadget.dev.release = kagen2_gadget_release;
dev->gadget.name = driver_name;
irqflags = 0;
if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE)
irqflags |= IRQF_TRIGGER_RISING;
if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE)
irqflags |= IRQF_TRIGGER_FALLING;
if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL)
irqflags |= IRQF_TRIGGER_HIGH;
if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
irqflags |= IRQF_TRIGGER_LOW;
base = iomem->start;
len = resource_size(iomem);
if (!request_mem_region(base, len, driver_name)) {
ret = -EBUSY;
goto err;
}
dev->base_addr = ioremap_nocache(base, len);
if (!dev->base_addr) {
ret = -EFAULT;
goto err_req;
}
printk("kagen2_plat_probe 6, 0x%x 0x%x\n", dev->base_addr, len);
// init low level usb
kagen2_lowlevel_init(dev);
// init usb software structure
for (i = 0; i < NUM_ENDPOINTS; ++i) {
struct ka_ep *ep = &dev->ep[i];
printk("kagen2_plat_probe %d %x\n", i, &dev->ep[i]);
ep->ep.name = ep_name[i];
ep->dev = dev;
ep->desc = NULL;
INIT_LIST_HEAD(&ep->queue);
ep->ep.maxpacket = ~0;
ep->ep.ops = &kagen2_ep_ops;
}
dev->ep[0].ep.maxpacket = 64;
dev->gadget.ep0 = &dev->ep[0].ep;
INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
printk("kagen2_plat_probe 8\n");
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);
dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512;
dev->ep[1].ep.maxpacket = dev->ep[2].ep.maxpacket = 512;
// unmask the irq 32 which is the usb irq
//ka2000_writel((ka2000_readl(0xa0006014) & 0xfffffffe), 0xa0006014);
ret = device_register(&dev->gadget.dev);
ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
platform_set_drvdata(pdev, dev);
// kernel thread
task = kthread_run(&example_thread, (void *)dev, "example_t");
return 0;
err_req:
err:
return ret;
}
static int __devexit
kagen2_plat_remove(struct platform_device *pdev)
{
struct kagen2 *dev = platform_get_drvdata(pdev);
release_mem_region(pdev->resource[0].start,
resource_size(&pdev->resource[0]));
kfree(dev);
return 0;
}
/*-------------------------------------------------------------------------*/
static struct platform_driver kagen2_plat_driver = {
.probe = kagen2_plat_probe,
.remove = kagen2_plat_remove,
.driver = {
.name = driver_name,
.owner = THIS_MODULE,
},
};
static int __init kagen2_init (void)
{
int ret;
printk("kagen2_init\n");
ret = platform_driver_register(&kagen2_plat_driver);
printk("kagen2_init %d\n", ret);
return ret;
}
module_init (kagen2_init);
static void __exit kagen2_cleanup (void)
{
platform_driver_unregister(&kagen2_plat_driver);
kthread_stop(task);
}
module_exit (kagen2_cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("KA");
MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html