Re: Linux USB file storage gadget with new UDC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux