MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_ALIAS("platform:r8a66597_hcd");
-#define DRIVER_VERSION "29 May 2007"
+#define DRIVER_VERSION "10 Apr 2008"
static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644);
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
"(default=0)");
+#endif
static unsigned short vif = LDRV;
module_param(vif, ushort, 0644);
r8a66597_write(r8a66597, val, devadd_reg);
}
-static int enable_controller(struct r8a66597 *r8a66597)
+static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
{
u16 tmp;
int i = 0;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ do {
+ r8a66597_write(r8a66597, SCKE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ err("register access fail.");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+#else
do {
r8a66597_write(r8a66597, USBE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0);
return -ENXIO;
}
} while ((tmp & SCKE) != SCKE);
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+
+ return 0;
+}
+
+static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
+{
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+ udelay(1);
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+#endif
+}
+
+static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val;
+
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+
+ r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
+ r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port));
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+}
+
+static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val, tmp;
+
+ r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+ r8a66597_write(r8a66597, 0, get_intsts_reg(port));
+
+ r8a66597_port_power(r8a66597, port, 0);
+
+ do {
+ tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+ udelay(640);
+ } while (tmp == EDGESTS);
- r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
- r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+ int ret, port;
+
+ ret = r8a66597_clock_enable(r8a66597);
+ if (ret < 0)
+ return ret;
r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
- r8a66597_bset(r8a66597, HSE, SYSCFG0);
- r8a66597_bset(r8a66597, HSE, SYSCFG1);
r8a66597_bset(r8a66597, USBE, SYSCFG0);
r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
r8a66597_bset(r8a66597, BRDY0, BRDYENB);
r8a66597_bset(r8a66597, BEMP0, BEMPENB);
- r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG);
- r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG);
-
r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
-
r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
- r8a66597_bclr(r8a66597, DTCHE, INTENB1);
- r8a66597_bset(r8a66597, ATTCHE, INTENB1);
- r8a66597_bclr(r8a66597, DTCHE, INTENB2);
- r8a66597_bset(r8a66597, ATTCHE, INTENB2);
+
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_enable_port(r8a66597, port);
return 0;
}
static void disable_controller(struct r8a66597 *r8a66597)
{
- u16 tmp;
+ int port;
r8a66597_write(r8a66597, 0, INTENB0);
- r8a66597_write(r8a66597, 0, INTENB1);
- r8a66597_write(r8a66597, 0, INTENB2);
r8a66597_write(r8a66597, 0, INTSTS0);
- r8a66597_write(r8a66597, 0, INTSTS1);
- r8a66597_write(r8a66597, 0, INTSTS2);
- r8a66597_port_power(r8a66597, 0, 0);
- r8a66597_port_power(r8a66597, 1, 0);
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_disable_port(r8a66597, port);
- do {
- tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
- udelay(640);
- } while (tmp == EDGESTS);
-
- r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0);
- r8a66597_bclr(r8a66597, DRPD, SYSCFG1);
- r8a66597_bclr(r8a66597, HSE, SYSCFG0);
- r8a66597_bclr(r8a66597, HSE, SYSCFG1);
-
- r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
- udelay(1);
- r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
- r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_clock_disable(r8a66597);
}
static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
PIPEBUF);
r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket,
PIPEMAXP);
- if (info->interval)
- info->interval--;
r8a66597_write(r8a66597, info->interval, PIPEPERI);
}
-
-
/* this function must be called with interrupt disabled */
static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
struct r8a66597_pipe *pipe,
struct urb *urb)
{
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
int i;
struct r8a66597_pipe_info *info = &pipe->info;
break;
}
}
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
}
/* this function must be called with interrupt disabled */
kfree(td);
if (urb) {
- urb->status = -ENODEV;
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+ urb);
+
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+ -ENODEV);
spin_lock(&r8a66597->lock);
}
break;
dev->dma_map = 0;
}
+static unsigned long get_timer_interval(struct urb *urb, __u8 interval)
+{
+ __u8 i;
+ unsigned long time = 1;
+
+ if (usb_pipeisoc(urb->pipe))
+ return 0;
+
+ if (get_r8a66597_usb_speed(urb->dev->speed) == HSMODE) {
+ for (i = 0; i < (interval - 1); i++)
+ time *= 2;
+ time = time * 125 / 1000; /* uSOF -> msec */
+ } else {
+ time = interval;
+ }
+
+ return time;
+}
+
/* this function must be called with interrupt disabled */
static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
struct usb_host_endpoint *hep,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = ep->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
info.type = get_r8a66597_type(ep->bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
info.buf_bsize = get_buf_bsize(info.pipenum);
- info.interval = ep->bInterval;
+ if (info.type == R8A66597_BULK) {
+ info.interval = 0;
+ info.timer_interval = 0;
+ } else {
+ if (ep->bInterval > IITV)
+ info.interval = IITV;
+ else
+ info.interval = ep->bInterval ? ep->bInterval - 1 : 0;
+ info.timer_interval = get_timer_interval(urb, ep->bInterval);
+ }
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
else
}
/* this function must be called with interrupt disabled */
-static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
+static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
+ u16 syssts)
{
- r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
- | (1 << USB_PORT_FEAT_C_CONNECTION);
+ if (syssts == SE0) {
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+ return;
+ }
+
+ if (syssts == FS_JSTS)
+ r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+ else if (syssts == LS_JSTS)
+ r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+
r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
}
struct r8a66597_td *td)
{
int i;
- u16 *p = (u16 *)td->urb->setup_packet;
+ __le16 *p = (__le16 *)td->urb->setup_packet;
unsigned long setup_addr = USBREQ;
r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, p[i], setup_addr);
+ r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
r8a66597_write(r8a66597, TRCLR,
td->pipe->pipetre);
r8a66597_write(r8a66597,
- (urb->transfer_buffer_length
- + td->maxpacket - 1)
- / td->maxpacket,
+ DIV_ROUND_UP
+ (urb->transfer_buffer_length,
+ td->maxpacket),
td->pipe->pipetrn);
r8a66597_bset(r8a66597, TRENB,
td->pipe->pipetre);
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
- r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+ r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
enable_irq_empty(r8a66597, 0);
} else {
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
pipe_start(r8a66597, td->pipe);
}
+static int is_set_address(unsigned char *setup_packet)
+{
+ if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+ setup_packet[1] == USB_REQ_SET_ADDRESS)
+ return 1;
+ else
+ return 0;
+}
+
/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
switch (td->type) {
case USB_PID_SETUP:
- if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+ if (is_set_address(td->urb->setup_packet)) {
td->set_address = 1;
td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
td->urb);
}
/* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
int restart = 0;
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
r8a66597->timeout_map &= ~(1 << pipenum);
if (likely(td)) {
- if (td->set_address && urb->status != 0)
+ if (td->set_address && (status != 0 || urb->unlinked))
r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
pipe_toggle_save(r8a66597, td->pipe, urb);
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
}
}
}
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
- done(r8a66597, td, pipenum, urb);
-}
-
static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
u16 tmp;
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
struct urb *urb;
int finish = 0;
+ int status = 0;
if (unlikely(!td))
return;
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("in fifo not ready (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
/* prepare parameters */
rcv_len = tmp & DTLN;
- bufsize = td->maxpacket;
if (usb_pipeisoc(urb->pipe)) {
buf = (u16 *)(urb->transfer_buffer +
urb->iso_frame_desc[td->iso_cnt].offset);
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
- if (rcv_len < bufsize)
- size = min(rcv_len, urb_len);
- else
- size = min(bufsize, urb_len);
+ bufsize = min(urb_len, (int) td->maxpacket);
+ if (rcv_len <= bufsize) {
+ size = rcv_len;
+ } else {
+ size = bufsize;
+ status = -EOVERFLOW;
+ finish = 1;
+ }
/* update parameters */
urb->actual_length += size;
if (rcv_len == 0)
td->zero_packet = 1;
- if ((size % td->maxpacket) > 0) {
+ if (rcv_len < bufsize) {
td->short_packet = 1;
- if (urb->transfer_buffer_length != urb->actual_length &&
- urb->transfer_flags & URB_SHORT_NOT_OK)
- td->urb->status = -EREMOTEIO;
}
if (usb_pipeisoc(urb->pipe)) {
urb->iso_frame_desc[td->iso_cnt].actual_length = size;
- urb->iso_frame_desc[td->iso_cnt].status = 0;
+ urb->iso_frame_desc[td->iso_cnt].status = status;
td->iso_cnt++;
+ finish = 0;
}
/* check transfer finish */
- if (check_transfer_finish(td, urb)) {
+ if (finish || check_transfer_finish(td, urb)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
finish = 1;
buf, size);
}
- if (finish && pipenum != 0) {
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, urb);
- }
+ if (finish && pipenum != 0)
+ finish_request(r8a66597, td, pipenum, urb, status);
}
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("out write fifo not ready. (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
}
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
struct urb *urb;
switch (td->type) {
case USB_PID_IN:
case USB_PID_OUT:
- if (urb->status != -EINPROGRESS) {
- finish = 1;
- break;
- }
if (check_transfer_finish(td, urb))
td->type = USB_PID_ACK;
break;
case USB_PID_SETUP:
- if (urb->status != -EINPROGRESS)
- finish = 1;
- else if (urb->transfer_buffer_length == urb->actual_length) {
+ if (urb->transfer_buffer_length == urb->actual_length)
td->type = USB_PID_ACK;
- urb->status = 0;
- } else if (usb_pipeout(urb->pipe))
+ else if (usb_pipeout(urb->pipe))
td->type = USB_PID_OUT;
else
td->type = USB_PID_IN;
break;
case USB_PID_ACK:
finish = 1;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
break;
}
- if (finish)
- finish_request(r8a66597, td, 0, urb);
+ if (finish || status != 0 || urb->unlinked)
+ finish_request(r8a66597, td, 0, urb, status);
else
start_transfer(r8a66597, td);
}
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
- if (td && td->urb) {
+ if (td) {
u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
if (pid == PID_NAK)
- td->urb->status = -ECONNRESET;
+ return -ECONNRESET;
else
- td->urb->status = -EPIPE;
+ return -EPIPE;
}
+ return 0;
}
static void irq_pipe_ready(struct r8a66597 *r8a66597)
packet_read(r8a66597, 0);
else
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type != USB_PID_OUT)
disable_irq_empty(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
if ((tmp & INBUFM) == 0) {
disable_irq_empty(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb,
+ 0);
}
}
}
u16 check;
u16 pipenum;
u16 mask;
+ int status;
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
- set_urb_error(r8a66597, 0);
+ status = get_urb_error(r8a66597, 0);
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, status);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
if (unlikely(!td))
continue;
- set_urb_error(r8a66597, pipenum);
+ status = get_urb_error(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
pipe_stop(r8a66597, td->pipe);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, status);
}
}
}
+static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597)
+{
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME));
+}
+
static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port)
{
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
rh->scount = R8A66597_MAX_SAMPLING;
- mod_timer(&r8a66597->rh_timer, jiffies + msecs_to_jiffies(50));
+ r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
+ | (1 << USB_PORT_FEAT_C_CONNECTION);
+ r8a66597_root_hub_start_polling(r8a66597);
}
static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
u16 intsts0, intsts1, intsts2;
u16 intenb0, intenb1, intenb2;
u16 mask0, mask1, mask2;
+ int status;
spin_lock(&r8a66597->lock);
}
if (mask1 & SIGN) {
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
- set_urb_error(r8a66597, 0);
- check_next_phase(r8a66597);
+ status = get_urb_error(r8a66597, 0);
+ check_next_phase(r8a66597, status);
}
if (mask1 & SACK) {
r8a66597_write(r8a66597, ~SACK, INTSTS1);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
}
if (mask0) {
if ((tmp & USBRST) == USBRST) {
r8a66597_mdfy(r8a66597, UACT, USBRST | UACT,
dvstctr_reg);
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
+ r8a66597_root_hub_start_polling(r8a66597);
} else
r8a66597_usb_connect(r8a66597, port);
}
+ if (!(rh->port & (1 << USB_PORT_FEAT_CONNECTION))) {
+ r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+ }
+
if (rh->scount > 0) {
tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
if (tmp == rh->old_syssts) {
rh->scount--;
- if (rh->scount == 0) {
- if (tmp == FS_JSTS) {
- r8a66597_bset(r8a66597, HSE,
- get_syscfg_reg(port));
- r8a66597_usb_preconnect(r8a66597, port);
- } else if (tmp == LS_JSTS) {
- r8a66597_bclr(r8a66597, HSE,
- get_syscfg_reg(port));
- r8a66597_usb_preconnect(r8a66597, port);
- } else if (tmp == SE0)
- r8a66597_bset(r8a66597, ATTCHE,
- get_intenb_reg(port));
- } else {
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
- }
+ if (rh->scount == 0)
+ r8a66597_check_syssts(r8a66597, port, tmp);
+ else
+ r8a66597_root_hub_start_polling(r8a66597);
} else {
rh->scount = R8A66597_MAX_SAMPLING;
rh->old_syssts = tmp;
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
+ r8a66597_root_hub_start_polling(r8a66597);
}
}
}
+static void r8a66597_interval_timer(unsigned long _r8a66597)
+{
+ struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+ unsigned long flags;
+ u16 pipenum;
+ struct r8a66597_td *td;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+
+ for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ if (!(r8a66597->interval_map & (1 << pipenum)))
+ continue;
+ if (timer_pending(&r8a66597->interval_timer[pipenum]))
+ continue;
+
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (td)
+ start_transfer(r8a66597, td);
+ }
+
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
static void r8a66597_td_timer(unsigned long _r8a66597)
{
struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
+ struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
- int ret = 0, request = 0;
+ int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
- goto error;
+ goto error_not_linked;
}
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto error_not_linked;
+
if (!hep->hcpriv) {
hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
GFP_ATOMIC);
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- ret = -EPIPE;
- goto error;
- }
urb->hcpriv = td;
- spin_unlock(&urb->lock);
if (request) {
- ret = start_transfer(r8a66597, td);
- if (ret < 0) {
- list_del(&td->queue);
- kfree(td);
+ if (td->pipe->info.timer_interval) {
+ r8a66597->interval_map |= 1 << td->pipenum;
+ mod_timer(&r8a66597->interval_timer[td->pipenum],
+ jiffies + msecs_to_jiffies(
+ td->pipe->info.timer_interval));
+ } else {
+ ret = start_transfer(r8a66597, td);
+ if (ret < 0) {
+ list_del(&td->queue);
+ kfree(td);
+ }
}
} else
set_td_timer(r8a66597, td);
error:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, td->pipenum);
disable_irq_empty(r8a66597, td->pipenum);
- done(r8a66597, td, td->pipenum, urb);
+ finish_request(r8a66597, td, td->pipenum, urb, status);
}
+ done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
- return 0;
+ return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
td = r8a66597_get_td(r8a66597, pipenum);
if (td)
urb = td->urb;
- done(r8a66597, td, pipenum, urb);
+ finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
kfree(hep->hcpriv);
hep->hcpriv = NULL;
spin_unlock_irqrestore(&r8a66597->lock, flags);
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
- *(u32 *)buf = rh->port;
+ *(__le32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
#if defined(CONFIG_PM)
static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
{
- pdev->dev.power.power_state = state;
return 0;
}
static int r8a66597_resume(struct platform_device *pdev)
{
- pdev->dev.power.power_state = PMSG_ON;
return 0;
}
#else /* if defined(CONFIG_PM) */
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
- iounmap((void *)r8a66597->reg);
usb_remove_hcd(hcd);
+ iounmap((void *)r8a66597->reg);
usb_put_hcd(hcd);
return 0;
}
init_timer(&r8a66597->td_timer[i]);
r8a66597->td_timer[i].function = r8a66597_td_timer;
r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+ setup_timer(&r8a66597->interval_timer[i],
+ r8a66597_interval_timer,
+ (unsigned long)r8a66597);
}
INIT_LIST_HEAD(&r8a66597->child_device);
hcd->rsrc_start = res->start;
- ret = usb_add_hcd(hcd, irq, 0);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (ret != 0) {
err("Failed to add hcd");
goto clean_up;
clean_up:
if (reg)
iounmap(reg);
- if (res)
- release_mem_region(res->start, 1);
return ret;
}
.resume = r8a66597_resume,
.driver = {
.name = (char *) hcd_name,
+ .owner = THIS_MODULE,
},
};