Merge remote-tracking branch 'kraxel/usb.28' into staging

This commit is contained in:
Anthony Liguori 2011-10-14 10:46:35 -05:00
commit bdc792d387
9 changed files with 180 additions and 84 deletions

View File

@ -880,6 +880,7 @@ static void ehci_reset(void *opaque)
}
if (devs[i] && devs[i]->attached) {
usb_attach(&s->ports[i]);
usb_send_msg(devs[i], USB_MSG_RESET);
}
}
ehci_queues_rip_all(s);
@ -978,8 +979,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
trace_usb_ehci_port_reset(port, 0);
if (dev && dev->attached) {
usb_attach(&s->ports[port]);
usb_send_msg(dev, USB_MSG_RESET);
usb_reset(&s->ports[port]);
*portsc &= ~PORTSC_CSC;
}

View File

@ -527,10 +527,21 @@ static int usb_keyboard_initfn(USBDevice *dev)
return usb_hid_initfn(dev, HID_KEYBOARD);
}
static int usb_ptr_post_load(void *opaque, int version_id)
{
USBHIDState *s = opaque;
if (s->dev.remote_wakeup) {
hid_pointer_activate(&s->hid);
}
return 0;
}
static const VMStateDescription vmstate_usb_ptr = {
.name = "usb-ptr",
.version_id = 1,
.minimum_version_id = 1,
.post_load = usb_ptr_post_load,
.fields = (VMStateField []) {
VMSTATE_USB_DEVICE(dev, USBHIDState),
VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),

View File

@ -207,10 +207,14 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
/*
* Just pass it along upstream for now.
*
* If we ever inplement usb 2.0 split transactions this will
* If we ever implement usb 2.0 split transactions this will
* become a little more complicated ...
*
* Can't use usb_packet_complete() here because packet->owner is
* cleared already, go call the ->complete() callback directly
* instead.
*/
usb_packet_complete(&s->dev, packet);
s->dev.port->ops->complete(s->dev.port, packet);
}
static void usb_hub_handle_reset(USBDevice *dev)
@ -289,7 +293,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
port->wPortStatus |= PORT_STAT_SUSPEND;
break;
case PORT_RESET:
if (dev) {
if (dev && dev->attached) {
usb_send_msg(dev, USB_MSG_RESET);
port->wPortChange |= PORT_STAT_C_RESET;
/* set enable bit */
@ -429,7 +433,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
dev = port->port.dev;
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) {
ret = usb_handle_packet(dev, p);
if (ret != USB_RET_NODEV) {
return ret;

View File

@ -325,7 +325,10 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
scsi_req_cancel(s->req);
if (s->req) {
scsi_req_cancel(s->req);
}
}
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)

View File

@ -150,7 +150,7 @@ static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
#define OHCI_TD_DI_SHIFT 21
#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT)
#define OHCI_TD_T0 (1<<24)
#define OHCI_TD_T1 (1<<24)
#define OHCI_TD_T1 (1<<25)
#define OHCI_TD_EC_SHIFT 26
#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
#define OHCI_TD_CC_SHIFT 28
@ -449,7 +449,7 @@ static void ohci_reset(void *opaque)
port = &ohci->rhport[i];
port->ctrl = 0;
if (port->port.dev && port->port.dev->attached) {
usb_attach(&port->port);
usb_reset(&port->port);
}
}
if (ohci->async_td) {
@ -872,7 +872,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
{
int dir;
size_t len = 0;
size_t len = 0, pktlen = 0;
#ifdef DEBUG_PACKET
const char *str = NULL;
#endif
@ -940,20 +940,30 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
len = (td.be - td.cbp) + 1;
}
if (len && dir != OHCI_TD_DIR_IN && !completion) {
ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
pktlen = len;
if (len && dir != OHCI_TD_DIR_IN) {
/* The endpoint may not allow us to transfer it all now */
pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
if (pktlen > len) {
pktlen = len;
}
if (!completion) {
ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 0);
}
}
}
flag_r = (td.flags & OHCI_TD_R) != 0;
#ifdef DEBUG_PACKET
DPRINTF(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
addr, (int64_t)len, str, flag_r, td.cbp, td.be);
DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64
" bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be);
if (len > 0 && dir != OHCI_TD_DIR_IN) {
if (pktlen > 0 && dir != OHCI_TD_DIR_IN) {
DPRINTF(" data:");
for (i = 0; i < len; i++)
for (i = 0; i < pktlen; i++) {
printf(" %.2x", ohci->usb_buf[i]);
}
DPRINTF("\n");
}
#endif
@ -982,7 +992,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
usb_packet_setup(&ohci->usb_packet, pid,
OHCI_BM(ed->flags, ED_FA),
OHCI_BM(ed->flags, ED_EN));
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@ -1005,12 +1015,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
DPRINTF("\n");
#endif
} else {
ret = len;
ret = pktlen;
}
}
/* Writeback */
if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
/* Transmission succeeded. */
if (ret == len) {
td.cbp = 0;
@ -1026,6 +1036,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
OHCI_SET_BM(td.flags, TD_EC, 0);
if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
/* Partial packet transfer: TD not ready to retire yet */
goto exit_no_retire;
}
/* Setting ED_C is part of the TD retirement process */
ed->head &= ~OHCI_ED_C;
if (td.flags & OHCI_TD_T0)
ed->head |= OHCI_ED_C;
@ -1066,6 +1082,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
i = OHCI_BM(td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
exit_no_retire:
ohci_put_td(ohci, addr, &td);
return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
}

View File

@ -341,7 +341,7 @@ static void uhci_reset(void *opaque)
port = &s->ports[i];
port->ctrl = 0x0080;
if (port->port.dev && port->port.dev->attached) {
usb_attach(&port->port);
usb_reset(&port->port);
}
}

View File

@ -33,6 +33,7 @@ void usb_attach(USBPort *port)
assert(dev != NULL);
assert(dev->attached);
assert(dev->state == USB_STATE_NOTATTACHED);
port->ops->attach(port);
usb_send_msg(dev, USB_MSG_ATTACH);
}
@ -42,10 +43,21 @@ void usb_detach(USBPort *port)
USBDevice *dev = port->dev;
assert(dev != NULL);
assert(dev->state != USB_STATE_NOTATTACHED);
port->ops->detach(port);
usb_send_msg(dev, USB_MSG_DETACH);
}
void usb_reset(USBPort *port)
{
USBDevice *dev = port->dev;
assert(dev != NULL);
usb_detach(port);
usb_attach(port);
usb_send_msg(dev, USB_MSG_RESET);
}
void usb_wakeup(USBDevice *dev)
{
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {

View File

@ -306,6 +306,7 @@ void usb_cancel_packet(USBPacket * p);
void usb_attach(USBPort *port);
void usb_detach(USBPort *port);
void usb_reset(USBPort *port);
void usb_wakeup(USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);

View File

@ -411,6 +411,100 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
}
}
static int usb_host_claim_port(USBHostDevice *s)
{
#ifdef USBDEVFS_CLAIM_PORT
char *h, hub_name[64], line[1024];
int hub_addr, portnr, ret;
snprintf(hub_name, sizeof(hub_name), "%d-%s",
s->match.bus_num, s->match.port);
/* try strip off last ".$portnr" to get hub */
h = strrchr(hub_name, '.');
if (h != NULL) {
portnr = atoi(h+1);
*h = '\0';
} else {
/* no dot in there -> it is the root hub */
snprintf(hub_name, sizeof(hub_name), "usb%d",
s->match.bus_num);
portnr = atoi(s->match.port);
}
if (!usb_host_read_file(line, sizeof(line), "devnum",
hub_name)) {
return -1;
}
if (sscanf(line, "%d", &hub_addr) != 1) {
return -1;
}
if (!usb_host_device_path) {
return -1;
}
snprintf(line, sizeof(line), "%s/%03d/%03d",
usb_host_device_path, s->match.bus_num, hub_addr);
s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
if (s->hub_fd < 0) {
return -1;
}
ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
if (ret < 0) {
close(s->hub_fd);
s->hub_fd = -1;
return -1;
}
trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
return 0;
#else
return -1;
#endif
}
static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
{
/* earlier Linux 2.4 do not support that */
#ifdef USBDEVFS_DISCONNECT
struct usbdevfs_ioctl ctrl;
int ret, interface;
for (interface = 0; interface < nb_interfaces; interface++) {
ctrl.ioctl_code = USBDEVFS_DISCONNECT;
ctrl.ifno = interface;
ctrl.data = 0;
ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
if (ret < 0 && errno != ENODATA) {
perror("USBDEVFS_DISCONNECT");
return -1;
}
}
#endif
return 0;
}
static int usb_linux_get_num_interfaces(USBHostDevice *s)
{
char device_name[64], line[1024];
int num_interfaces = 0;
if (usb_fs_type != USB_FS_SYS) {
return -1;
}
sprintf(device_name, "%d-%s", s->bus_num, s->port);
if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
device_name)) {
return -1;
}
if (sscanf(line, "%d", &num_interfaces) != 1) {
return -1;
}
return num_interfaces;
}
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
{
const char *op = NULL;
@ -462,22 +556,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
}
nb_interfaces = dev->descr[i + 4];
#ifdef USBDEVFS_DISCONNECT
/* earlier Linux 2.4 do not support that */
{
struct usbdevfs_ioctl ctrl;
for (interface = 0; interface < nb_interfaces; interface++) {
ctrl.ioctl_code = USBDEVFS_DISCONNECT;
ctrl.ifno = interface;
ctrl.data = 0;
op = "USBDEVFS_DISCONNECT";
ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
if (ret < 0 && errno != ENODATA) {
goto fail;
}
}
if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
goto fail;
}
#endif
/* XXX: only grab if all interfaces are free */
for (interface = 0; interface < nb_interfaces; interface++) {
@ -840,14 +921,28 @@ static int usb_host_set_address(USBHostDevice *s, int addr)
static int usb_host_set_config(USBHostDevice *s, int config)
{
int ret, first = 1;
trace_usb_host_set_config(s->bus_num, s->addr, config);
usb_host_release_interfaces(s);
int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
again:
ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
if (ret < 0 && errno == EBUSY && first) {
/* happens if usb device is in use by host drivers */
int count = usb_linux_get_num_interfaces(s);
if (count > 0) {
DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
usb_host_disconnect_ifaces(s, count);
first = 0;
goto again;
}
}
if (ret < 0) {
return ctrl_error();
}
@ -1301,56 +1396,9 @@ static int usb_host_initfn(USBDevice *dev)
qemu_add_exit_notifier(&s->exit);
usb_host_auto_check(NULL);
#ifdef USBDEVFS_CLAIM_PORT
if (s->match.bus_num != 0 && s->match.port != NULL) {
char *h, hub_name[64], line[1024];
int hub_addr, portnr, ret;
snprintf(hub_name, sizeof(hub_name), "%d-%s",
s->match.bus_num, s->match.port);
/* try strip off last ".$portnr" to get hub */
h = strrchr(hub_name, '.');
if (h != NULL) {
portnr = atoi(h+1);
*h = '\0';
} else {
/* no dot in there -> it is the root hub */
snprintf(hub_name, sizeof(hub_name), "usb%d",
s->match.bus_num);
portnr = atoi(s->match.port);
}
if (!usb_host_read_file(line, sizeof(line), "devnum",
hub_name)) {
goto out;
}
if (sscanf(line, "%d", &hub_addr) != 1) {
goto out;
}
if (!usb_host_device_path) {
goto out;
}
snprintf(line, sizeof(line), "%s/%03d/%03d",
usb_host_device_path, s->match.bus_num, hub_addr);
s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
if (s->hub_fd < 0) {
goto out;
}
ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
if (ret < 0) {
close(s->hub_fd);
s->hub_fd = -1;
goto out;
}
trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
usb_host_claim_port(s);
}
out:
#endif
return 0;
}