Changeset 450448d in mainline for kernel/genarch/src/drivers/via-cuda/cuda.c
- Timestamp:
- 2009-07-11T21:47:46Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9a61ba5
- Parents:
- 4b2c458c
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/genarch/src/drivers/via-cuda/cuda.c
r4b2c458c r450448d 42 42 #include <synch/spinlock.h> 43 43 44 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len); 44 static irq_ownership_t cuda_claim(irq_t *irq); 45 static void cuda_irq_handler(irq_t *irq); 46 45 47 static void cuda_irq_listen(irq_t *irq); 46 48 static void cuda_irq_receive(irq_t *irq); 47 49 static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len); 50 static void cuda_irq_send_start(irq_t *irq); 51 static void cuda_irq_send(irq_t *irq); 52 53 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len); 54 static void cuda_send_start(cuda_instance_t *instance); 55 static void cuda_autopoll_set(cuda_instance_t *instance, bool enable); 48 56 49 57 /** B register fields */ … … 68 76 }; 69 77 70 #include <print.h> 71 static irq_ownership_t cuda_claim(irq_t *irq) 72 { 73 cuda_instance_t *instance = irq->instance; 74 cuda_t *dev = instance->cuda; 75 uint8_t ifr; 76 77 ifr = pio_read_8(&dev->ifr); 78 79 if ((ifr & SR_INT) == 0) 80 return IRQ_DECLINE; 81 82 return IRQ_ACCEPT; 83 } 84 85 static void cuda_irq_handler(irq_t *irq) 86 { 87 cuda_instance_t *instance = irq->instance; 88 uint8_t rbuf[CUDA_RCV_BUF_SIZE]; 89 size_t len; 90 bool handle; 91 92 handle = false; 93 len = 0; 94 95 spinlock_lock(&instance->dev_lock); 96 97 /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */ 98 pio_write_8(&instance->cuda->ifr, SR_INT); 99 100 switch (instance->xstate) { 101 case cx_listen: cuda_irq_listen(irq); break; 102 case cx_receive: cuda_irq_receive(irq); break; 103 case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len); 104 handle = true; break; 105 } 106 107 spinlock_unlock(&instance->dev_lock); 108 109 /* Handle an incoming packet. */ 110 if (handle) 111 cuda_packet_handle(instance, rbuf, len); 112 } 113 114 /** Interrupt in listen state. 115 * 116 * Start packet reception. 117 */ 118 static void cuda_irq_listen(irq_t *irq) 119 { 120 cuda_instance_t *instance = irq->instance; 121 cuda_t *dev = instance->cuda; 122 uint8_t b; 123 124 b = pio_read_8(&dev->b); 125 126 if ((b & TREQ) != 0) { 127 printf("cuda_irq_listen: no TREQ?!\n"); 128 return; 129 } 130 131 pio_read_8(&dev->sr); 132 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); 133 instance->xstate = cx_receive; 134 } 135 136 /** Interrupt in receive state. 137 * 138 * Receive next byte of packet. 139 */ 140 static void cuda_irq_receive(irq_t *irq) 141 { 142 cuda_instance_t *instance = irq->instance; 143 cuda_t *dev = instance->cuda; 144 uint8_t b, data; 145 146 data = pio_read_8(&dev->sr); 147 if (instance->bidx < CUDA_RCV_BUF_SIZE) 148 instance->rcv_buf[instance->bidx++] = data; 149 150 b = pio_read_8(&dev->b); 151 152 if ((b & TREQ) == 0) { 153 pio_write_8(&dev->b, b ^ TACK); 154 } else { 155 pio_write_8(&dev->b, b | TACK | TIP); 156 instance->xstate = cx_rcv_end; 157 } 158 } 159 160 /** Interrupt in rcv_end state. 161 * 162 * Terminate packet reception. Either go back to listen state or start 163 * receiving another packet if CUDA has one for us. 164 */ 165 static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len) 166 { 167 cuda_instance_t *instance = irq->instance; 168 cuda_t *dev = instance->cuda; 169 uint8_t data, b; 170 171 b = pio_read_8(&dev->b); 172 data = pio_read_8(&dev->sr); 173 174 instance->xstate = cx_listen; 175 176 if ((b & TREQ) == 0) { 177 instance->xstate = cx_receive; 178 pio_write_8(&dev->b, b & ~TIP); 179 } else { 180 instance->xstate = cx_listen; 181 } 182 183 memcpy(buf, instance->rcv_buf, instance->bidx); 184 *len = instance->bidx; 185 instance->bidx = 0; 186 } 187 188 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len) 189 { 190 if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c 191 && data[2] != 0x8c)) 192 return; 193 194 /* The packet contains one or two scancodes. */ 195 if (data[3] != 0xff) 196 indev_push_character(instance->kbrdin, data[3]); 197 if (data[4] != 0xff) 198 indev_push_character(instance->kbrdin, data[4]); 199 } 78 /** Packet types */ 79 enum { 80 PT_ADB = 0x00, 81 PT_CUDA = 0x01 82 }; 83 84 /** CUDA packet types */ 85 enum { 86 CPT_AUTOPOLL = 0x01 87 }; 200 88 201 89 cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg) … … 208 96 instance->xstate = cx_listen; 209 97 instance->bidx = 0; 98 instance->snd_bytes = 0; 210 99 211 100 spinlock_initialize(&instance->dev_lock, "cuda_dev"); … … 228 117 } 229 118 119 #include <print.h> 230 120 void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin) 231 121 { … … 241 131 pio_write_8(&dev->ier, TIP | TREQ); 242 132 pio_write_8(&dev->ier, IER_SET | SR_INT); 243 } 133 134 /* Enable ADB autopolling. */ 135 cuda_autopoll_set(instance, true); 136 } 137 138 static irq_ownership_t cuda_claim(irq_t *irq) 139 { 140 cuda_instance_t *instance = irq->instance; 141 cuda_t *dev = instance->cuda; 142 uint8_t ifr; 143 144 spinlock_lock(&instance->dev_lock); 145 ifr = pio_read_8(&dev->ifr); 146 spinlock_unlock(&instance->dev_lock); 147 148 if ((ifr & SR_INT) == 0) 149 return IRQ_DECLINE; 150 151 return IRQ_ACCEPT; 152 } 153 154 static void cuda_irq_handler(irq_t *irq) 155 { 156 cuda_instance_t *instance = irq->instance; 157 uint8_t rbuf[CUDA_RCV_BUF_SIZE]; 158 size_t len; 159 bool handle; 160 161 handle = false; 162 len = 0; 163 164 spinlock_lock(&instance->dev_lock); 165 166 /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */ 167 pio_write_8(&instance->cuda->ifr, SR_INT); 168 169 switch (instance->xstate) { 170 case cx_listen: cuda_irq_listen(irq); break; 171 case cx_receive: cuda_irq_receive(irq); break; 172 case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len); 173 handle = true; break; 174 case cx_send_start: cuda_irq_send_start(irq); break; 175 case cx_send: cuda_irq_send(irq); break; 176 } 177 178 spinlock_unlock(&instance->dev_lock); 179 180 /* Handle an incoming packet. */ 181 if (handle) 182 cuda_packet_handle(instance, rbuf, len); 183 } 184 185 /** Interrupt in listen state. 186 * 187 * Start packet reception. 188 */ 189 static void cuda_irq_listen(irq_t *irq) 190 { 191 cuda_instance_t *instance = irq->instance; 192 cuda_t *dev = instance->cuda; 193 uint8_t b; 194 195 b = pio_read_8(&dev->b); 196 197 if ((b & TREQ) != 0) { 198 printf("cuda_irq_listen: no TREQ?!\n"); 199 return; 200 } 201 202 pio_read_8(&dev->sr); 203 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); 204 instance->xstate = cx_receive; 205 } 206 207 /** Interrupt in receive state. 208 * 209 * Receive next byte of packet. 210 */ 211 static void cuda_irq_receive(irq_t *irq) 212 { 213 cuda_instance_t *instance = irq->instance; 214 cuda_t *dev = instance->cuda; 215 uint8_t b, data; 216 217 data = pio_read_8(&dev->sr); 218 if (instance->bidx < CUDA_RCV_BUF_SIZE) 219 instance->rcv_buf[instance->bidx++] = data; 220 221 b = pio_read_8(&dev->b); 222 223 if ((b & TREQ) == 0) { 224 pio_write_8(&dev->b, b ^ TACK); 225 } else { 226 pio_write_8(&dev->b, b | TACK | TIP); 227 instance->xstate = cx_rcv_end; 228 } 229 } 230 231 /** Interrupt in rcv_end state. 232 * 233 * Terminate packet reception. Either go back to listen state or start 234 * receiving another packet if CUDA has one for us. 235 */ 236 static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len) 237 { 238 cuda_instance_t *instance = irq->instance; 239 cuda_t *dev = instance->cuda; 240 uint8_t data, b; 241 242 b = pio_read_8(&dev->b); 243 data = pio_read_8(&dev->sr); 244 245 if ((b & TREQ) == 0) { 246 instance->xstate = cx_receive; 247 pio_write_8(&dev->b, b & ~TIP); 248 } else { 249 instance->xstate = cx_listen; 250 cuda_send_start(instance); 251 } 252 253 memcpy(buf, instance->rcv_buf, instance->bidx); 254 *len = instance->bidx; 255 instance->bidx = 0; 256 } 257 258 /** Interrupt in send_start state. 259 * 260 * Process result of sending first byte (and send second on success). 261 */ 262 static void cuda_irq_send_start(irq_t *irq) 263 { 264 cuda_instance_t *instance = irq->instance; 265 cuda_t *dev = instance->cuda; 266 uint8_t b; 267 268 b = pio_read_8(&dev->b); 269 270 if ((b & TREQ) == 0) { 271 /* Collision */ 272 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); 273 pio_read_8(&dev->sr); 274 pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK); 275 instance->xstate = cx_listen; 276 return; 277 } 278 279 pio_write_8(&dev->sr, instance->snd_buf[1]); 280 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); 281 instance->bidx = 2; 282 283 instance->xstate = cx_send; 284 } 285 286 /** Interrupt in send state. 287 * 288 * Send next byte or terminate transmission. 289 */ 290 static void cuda_irq_send(irq_t *irq) 291 { 292 cuda_instance_t *instance = irq->instance; 293 cuda_t *dev = instance->cuda; 294 295 if (instance->bidx < instance->snd_bytes) { 296 /* Send next byte. */ 297 pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]); 298 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); 299 return; 300 } 301 302 /* End transfer. */ 303 instance->snd_bytes = 0; 304 instance->bidx = 0; 305 306 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); 307 pio_read_8(&dev->sr); 308 pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP); 309 310 instance->xstate = cx_listen; 311 /* TODO: Match reply with request. */ 312 } 313 314 static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len) 315 { 316 if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c 317 && data[2] != 0x8c)) 318 return; 319 320 /* The packet contains one or two scancodes. */ 321 if (data[3] != 0xff) 322 indev_push_character(instance->kbrdin, data[3]); 323 if (data[4] != 0xff) 324 indev_push_character(instance->kbrdin, data[4]); 325 } 326 327 static void cuda_autopoll_set(cuda_instance_t *instance, bool enable) 328 { 329 instance->snd_buf[0] = PT_CUDA; 330 instance->snd_buf[1] = CPT_AUTOPOLL; 331 instance->snd_buf[2] = enable ? 0x01 : 0x00; 332 instance->snd_bytes = 3; 333 instance->bidx = 0; 334 335 cuda_send_start(instance); 336 } 337 338 static void cuda_send_start(cuda_instance_t *instance) 339 { 340 cuda_t *dev = instance->cuda; 341 342 ASSERT(instance->xstate == cx_listen); 343 344 if (instance->snd_bytes == 0) 345 return; 346 347 /* Check for incoming data. */ 348 if ((pio_read_8(&dev->b) & TREQ) == 0) 349 return; 350 351 pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT); 352 pio_write_8(&dev->sr, instance->snd_buf[0]); 353 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); 354 355 instance->xstate = cx_send_start; 356 } 357 244 358 245 359 /** @}
Note:
See TracChangeset
for help on using the changeset viewer.