Commit 89b9b79f340f5799c29ab8178231377026c301e4

Authored by aliguori
1 parent 4b096fc9

usb: generic packet handler cleanup and documentation (Max Krasnyansky)

A bit better documentation of the USB device API, namely
return codes.
Rewrite of usb_generic_handle_packet() to make it more
reable and easier to follow.

Signed-off-by: Max Krasnyansky <maxk@kernel.org>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5049 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 179 additions and 121 deletions
hw/usb.c
... ... @@ -3,6 +3,8 @@
3 3 *
4 4 * Copyright (c) 2005 Fabrice Bellard
5 5 *
  6 + * 2008 Generic packet handler rewrite by Max Krasnyansky
  7 + *
6 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 9 * of this software and associated documentation files (the "Software"), to deal
8 10 * in the Software without restriction, including without limitation the rights
... ... @@ -30,6 +32,7 @@ void usb_attach(USBPort *port, USBDevice *dev)
30 32 }
31 33  
32 34 /**********************/
  35 +
33 36 /* generic USB device helpers (you are not forced to use them when
34 37 writing your USB device driver, but they help handling the
35 38 protocol)
... ... @@ -39,141 +42,164 @@ void usb_attach(USBPort *port, USBDevice *dev)
39 42 #define SETUP_STATE_DATA 1
40 43 #define SETUP_STATE_ACK 2
41 44  
42   -int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
  45 +static int do_token_setup(USBDevice *s, USBPacket *p)
  46 +{
  47 + int request, value, index;
  48 + int ret = 0;
  49 +
  50 + if (p->len != 8)
  51 + return USB_RET_STALL;
  52 +
  53 + memcpy(s->setup_buf, p->data, 8);
  54 + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
  55 + s->setup_index = 0;
  56 +
  57 + request = (s->setup_buf[0] << 8) | s->setup_buf[1];
  58 + value = (s->setup_buf[3] << 8) | s->setup_buf[2];
  59 + index = (s->setup_buf[5] << 8) | s->setup_buf[4];
  60 +
  61 + if (s->setup_buf[0] & USB_DIR_IN) {
  62 + ret = s->handle_control(s, request, value, index,
  63 + s->setup_len, s->data_buf);
  64 + if (ret < 0)
  65 + return ret;
  66 +
  67 + if (ret < s->setup_len)
  68 + s->setup_len = ret;
  69 + s->setup_state = SETUP_STATE_DATA;
  70 + } else {
  71 + if (s->setup_len == 0)
  72 + s->setup_state = SETUP_STATE_ACK;
  73 + else
  74 + s->setup_state = SETUP_STATE_DATA;
  75 + }
  76 +
  77 + return ret;
  78 +}
  79 +
  80 +static int do_token_in(USBDevice *s, USBPacket *p)
43 81 {
44   - int l, ret = 0;
45   - int len = p->len;
46   - uint8_t *data = p->data;
  82 + int request, value, index;
  83 + int ret = 0;
  84 +
  85 + if (p->devep != 0)
  86 + return s->handle_data(s, p);
  87 +
  88 + request = (s->setup_buf[0] << 8) | s->setup_buf[1];
  89 + value = (s->setup_buf[3] << 8) | s->setup_buf[2];
  90 + index = (s->setup_buf[5] << 8) | s->setup_buf[4];
  91 +
  92 + switch(s->setup_state) {
  93 + case SETUP_STATE_ACK:
  94 + if (!(s->setup_buf[0] & USB_DIR_IN)) {
  95 + s->setup_state = SETUP_STATE_IDLE;
  96 + ret = s->handle_control(s, request, value, index,
  97 + s->setup_len, s->data_buf);
  98 + if (ret > 0)
  99 + return 0;
  100 + return ret;
  101 + }
  102 +
  103 + /* return 0 byte */
  104 + return 0;
  105 +
  106 + case SETUP_STATE_DATA:
  107 + if (s->setup_buf[0] & USB_DIR_IN) {
  108 + int len = s->setup_len - s->setup_index;
  109 + if (len > p->len)
  110 + len = p->len;
  111 + memcpy(p->data, s->data_buf + s->setup_index, len);
  112 + s->setup_index += len;
  113 + if (s->setup_index >= s->setup_len)
  114 + s->setup_state = SETUP_STATE_ACK;
  115 + return len;
  116 + }
  117 +
  118 + s->setup_state = SETUP_STATE_IDLE;
  119 + return USB_RET_STALL;
  120 +
  121 + default:
  122 + return USB_RET_STALL;
  123 + }
  124 +}
  125 +
  126 +static int do_token_out(USBDevice *s, USBPacket *p)
  127 +{
  128 + if (p->devep != 0)
  129 + return s->handle_data(s, p);
  130 +
  131 + switch(s->setup_state) {
  132 + case SETUP_STATE_ACK:
  133 + if (s->setup_buf[0] & USB_DIR_IN) {
  134 + s->setup_state = SETUP_STATE_IDLE;
  135 + /* transfer OK */
  136 + } else {
  137 + /* ignore additional output */
  138 + }
  139 + return 0;
  140 +
  141 + case SETUP_STATE_DATA:
  142 + if (!(s->setup_buf[0] & USB_DIR_IN)) {
  143 + int len = s->setup_len - s->setup_index;
  144 + if (len > p->len)
  145 + len = p->len;
  146 + memcpy(s->data_buf + s->setup_index, p->data, len);
  147 + s->setup_index += len;
  148 + if (s->setup_index >= s->setup_len)
  149 + s->setup_state = SETUP_STATE_ACK;
  150 + return len;
  151 + }
  152 +
  153 + s->setup_state = SETUP_STATE_IDLE;
  154 + return USB_RET_STALL;
  155 +
  156 + default:
  157 + return USB_RET_STALL;
  158 + }
  159 +}
47 160  
  161 +/*
  162 + * Generic packet handler.
  163 + * Called by the HC (host controller).
  164 + *
  165 + * Returns length of the transaction or one of the USB_RET_XXX codes.
  166 + */
  167 +int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
  168 +{
48 169 switch(p->pid) {
49 170 case USB_MSG_ATTACH:
50 171 s->state = USB_STATE_ATTACHED;
51   - break;
  172 + return 0;
  173 +
52 174 case USB_MSG_DETACH:
53 175 s->state = USB_STATE_NOTATTACHED;
54   - break;
  176 + return 0;
  177 +
55 178 case USB_MSG_RESET:
56 179 s->remote_wakeup = 0;
57 180 s->addr = 0;
58 181 s->state = USB_STATE_DEFAULT;
59 182 s->handle_reset(s);
60   - break;
  183 + return 0;
  184 + }
  185 +
  186 + /* Rest of the PIDs must match our address */
  187 + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
  188 + return USB_RET_NODEV;
  189 +
  190 + switch (p->pid) {
61 191 case USB_TOKEN_SETUP:
62   - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
63   - return USB_RET_NODEV;
64   - if (len != 8)
65   - goto fail;
66   - memcpy(s->setup_buf, data, 8);
67   - s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
68   - s->setup_index = 0;
69   - if (s->setup_buf[0] & USB_DIR_IN) {
70   - ret = s->handle_control(s,
71   - (s->setup_buf[0] << 8) | s->setup_buf[1],
72   - (s->setup_buf[3] << 8) | s->setup_buf[2],
73   - (s->setup_buf[5] << 8) | s->setup_buf[4],
74   - s->setup_len,
75   - s->data_buf);
76   - if (ret < 0)
77   - return ret;
78   - if (ret < s->setup_len)
79   - s->setup_len = ret;
80   - s->setup_state = SETUP_STATE_DATA;
81   - } else {
82   - if (s->setup_len == 0)
83   - s->setup_state = SETUP_STATE_ACK;
84   - else
85   - s->setup_state = SETUP_STATE_DATA;
86   - }
87   - break;
  192 + return do_token_setup(s, p);
  193 +
88 194 case USB_TOKEN_IN:
89   - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
90   - return USB_RET_NODEV;
91   - switch(p->devep) {
92   - case 0:
93   - switch(s->setup_state) {
94   - case SETUP_STATE_ACK:
95   - if (!(s->setup_buf[0] & USB_DIR_IN)) {
96   - s->setup_state = SETUP_STATE_IDLE;
97   - ret = s->handle_control(s,
98   - (s->setup_buf[0] << 8) | s->setup_buf[1],
99   - (s->setup_buf[3] << 8) | s->setup_buf[2],
100   - (s->setup_buf[5] << 8) | s->setup_buf[4],
101   - s->setup_len,
102   - s->data_buf);
103   - if (ret > 0)
104   - ret = 0;
105   - } else {
106   - /* return 0 byte */
107   - }
108   - break;
109   - case SETUP_STATE_DATA:
110   - if (s->setup_buf[0] & USB_DIR_IN) {
111   - l = s->setup_len - s->setup_index;
112   - if (l > len)
113   - l = len;
114   - memcpy(data, s->data_buf + s->setup_index, l);
115   - s->setup_index += l;
116   - if (s->setup_index >= s->setup_len)
117   - s->setup_state = SETUP_STATE_ACK;
118   - ret = l;
119   - } else {
120   - s->setup_state = SETUP_STATE_IDLE;
121   - goto fail;
122   - }
123   - break;
124   - default:
125   - goto fail;
126   - }
127   - break;
128   - default:
129   - ret = s->handle_data(s, p);
130   - break;
131   - }
132   - break;
  195 + return do_token_in(s, p);
  196 +
133 197 case USB_TOKEN_OUT:
134   - if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
135   - return USB_RET_NODEV;
136   - switch(p->devep) {
137   - case 0:
138   - switch(s->setup_state) {
139   - case SETUP_STATE_ACK:
140   - if (s->setup_buf[0] & USB_DIR_IN) {
141   - s->setup_state = SETUP_STATE_IDLE;
142   - /* transfer OK */
143   - } else {
144   - /* ignore additional output */
145   - }
146   - break;
147   - case SETUP_STATE_DATA:
148   - if (!(s->setup_buf[0] & USB_DIR_IN)) {
149   - l = s->setup_len - s->setup_index;
150   - if (l > len)
151   - l = len;
152   - memcpy(s->data_buf + s->setup_index, data, l);
153   - s->setup_index += l;
154   - if (s->setup_index >= s->setup_len)
155   - s->setup_state = SETUP_STATE_ACK;
156   - ret = l;
157   - } else {
158   - s->setup_state = SETUP_STATE_IDLE;
159   - goto fail;
160   - }
161   - break;
162   - default:
163   - goto fail;
164   - }
165   - break;
166   - default:
167   - ret = s->handle_data(s, p);
168   - break;
169   - }
170   - break;
  198 + return do_token_out(s, p);
  199 +
171 200 default:
172   - fail:
173   - ret = USB_RET_STALL;
174   - break;
  201 + return USB_RET_STALL;
175 202 }
176   - return ret;
177 203 }
178 204  
179 205 /* XXX: fix overflow */
... ... @@ -200,5 +226,6 @@ void usb_send_msg(USBDevice *dev, int msg)
200 226 memset(&p, 0, sizeof(p));
201 227 p.pid = msg;
202 228 dev->handle_packet(dev, &p);
203   -}
204 229  
  230 + /* This _must_ be synchronous */
  231 +}
... ...
hw/usb.h
... ... @@ -120,18 +120,49 @@ typedef struct USBPacket USBPacket;
120 120 /* definition of a USB device */
121 121 struct USBDevice {
122 122 void *opaque;
  123 +
  124 + /*
  125 + * Process USB packet.
  126 + * Called by the HC (Host Controller).
  127 + *
  128 + * Returns length of the transaction
  129 + * or one of the USB_RET_XXX codes.
  130 + */
123 131 int (*handle_packet)(USBDevice *dev, USBPacket *p);
  132 +
  133 + /*
  134 + * Called when device is destroyed.
  135 + */
124 136 void (*handle_destroy)(USBDevice *dev);
125 137  
126 138 int speed;
127 139  
128 140 /* The following fields are used by the generic USB device
129   - layer. They are here just to avoid creating a new structure for
130   - them. */
  141 + layer. They are here just to avoid creating a new structure
  142 + for them. */
  143 +
  144 + /*
  145 + * Reset the device
  146 + */
131 147 void (*handle_reset)(USBDevice *dev);
  148 +
  149 + /*
  150 + * Process control request.
  151 + * Called from handle_packet().
  152 + *
  153 + * Returns length or one of the USB_RET_ codes.
  154 + */
132 155 int (*handle_control)(USBDevice *dev, int request, int value,
133 156 int index, int length, uint8_t *data);
  157 +
  158 + /*
  159 + * Process data transfers (both BULK and ISOC).
  160 + * Called from handle_packet().
  161 + *
  162 + * Returns length or one of the USB_RET_ codes.
  163 + */
134 164 int (*handle_data)(USBDevice *dev, USBPacket *p);
  165 +
135 166 uint8_t addr;
136 167 char devname[32];
137 168  
... ...