OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------ |
| 2 // <copyright file="hif.c" company="Atheros"> |
| 3 // Copyright (c) 2004-2008 Atheros Corporation. All rights reserved. |
| 4 // |
| 5 // This program is free software; you can redistribute it and/or modify |
| 6 // it under the terms of the GNU General Public License version 2 as |
| 7 // published by the Free Software Foundation; |
| 8 // |
| 9 // Software distributed under the License is distributed on an "AS |
| 10 // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 11 // implied. See the License for the specific language governing |
| 12 // rights and limitations under the License. |
| 13 // |
| 14 // |
| 15 //------------------------------------------------------------------------------ |
| 16 //============================================================================== |
| 17 // HIF layer reference implementation for Linux Native MMC stack |
| 18 // |
| 19 // Author(s): ="Atheros" |
| 20 //============================================================================== |
| 21 #include <linux/mmc/card.h> |
| 22 #include <linux/mmc/sdio_func.h> |
| 23 #include <linux/mmc/sdio_ids.h> |
| 24 #include <linux/mmc/sdio.h> |
| 25 #include <linux/kthread.h> |
| 26 |
| 27 /* by default setup a bounce buffer for the data packets, if the underlying host
controller driver |
| 28 does not use DMA you may be able to skip this step and save the memory alloca
tion and transfer time */ |
| 29 #define HIF_USE_DMA_BOUNCE_BUFFER 1 |
| 30 #include "hif_internal.h" |
| 31 #define ATH_MODULE_NAME hif |
| 32 #include "a_debug.h" |
| 33 |
| 34 |
| 35 #if HIF_USE_DMA_BOUNCE_BUFFER |
| 36 /* macro to check if DMA buffer is WORD-aligned and DMA-able. Most host control
lers assume the |
| 37 * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
|
| 38 * virt_addr_valid check fails on stack memory. |
| 39 */ |
| 40 #define BUFFER_NEEDS_BOUNCE(buffer) (((A_UINT32)(buffer) & 0x3) || !virt_addr_v
alid((buffer))) |
| 41 #else |
| 42 #define BUFFER_NEEDS_BOUNCE(buffer) (FALSE) |
| 43 #endif |
| 44 |
| 45 static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id
*id); |
| 46 static void hifDeviceRemoved(struct sdio_func *func); |
| 47 static HIF_DEVICE *addHifDevice(struct sdio_func *func); |
| 48 static HIF_DEVICE *getHifDevice(struct sdio_func *func); |
| 49 static void delHifDevice(HIF_DEVICE * device); |
| 50 static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, uns
igned char byte); |
| 51 |
| 52 int reset_sdio_on_unload = 0; |
| 53 module_param(reset_sdio_on_unload, int, 0644); |
| 54 |
| 55 /* ------ Static Variables ------ */ |
| 56 static const struct sdio_device_id ar6k_id_table[] = { |
| 57 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x0)) }, |
| 58 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x1)) }, |
| 59 { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0)) }, |
| 60 { /* null */ }, |
| 61 }; |
| 62 MODULE_DEVICE_TABLE(sdio, ar6k_id_table); |
| 63 |
| 64 static struct sdio_driver ar6k_driver = { |
| 65 .name = "ar6k_wlan", |
| 66 .id_table = ar6k_id_table, |
| 67 .probe = hifDeviceInserted, |
| 68 .remove = hifDeviceRemoved, |
| 69 }; |
| 70 /* make sure we only unregister when registered. */ |
| 71 static int registered = 0; |
| 72 |
| 73 OSDRV_CALLBACKS osdrvCallbacks; |
| 74 extern A_UINT32 onebitmode; |
| 75 extern A_UINT32 busspeedlow; |
| 76 extern A_UINT32 debughif; |
| 77 |
| 78 static BUS_REQUEST *hifAllocateBusRequest(HIF_DEVICE *device); |
| 79 static void hifFreeBusRequest(HIF_DEVICE *device, BUS_REQUEST *busrequest); |
| 80 static void ResetAllCards(void); |
| 81 |
| 82 #ifdef DEBUG |
| 83 |
| 84 ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, |
| 85 "hif", |
| 86 "(Linux MMC) Host Interconnect Framework", |
| 87 ATH_DEBUG_MASK_DEFAULTS, |
| 88 0, |
| 89 NULL); |
| 90 |
| 91 #endif |
| 92 |
| 93 |
| 94 /* ------ Functions ------ */ |
| 95 A_STATUS HIFInit(OSDRV_CALLBACKS *callbacks) |
| 96 { |
| 97 int status; |
| 98 AR_DEBUG_ASSERT(callbacks != NULL); |
| 99 |
| 100 A_REGISTER_MODULE_DEBUG_INFO(hif); |
| 101 |
| 102 /* store the callback handlers */ |
| 103 osdrvCallbacks = *callbacks; |
| 104 |
| 105 /* Register with bus driver core */ |
| 106 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFInit registering\n")); |
| 107 registered = 1; |
| 108 status = sdio_register_driver(&ar6k_driver); |
| 109 AR_DEBUG_ASSERT(status==0); |
| 110 |
| 111 if (status != 0) { |
| 112 return A_ERROR; |
| 113 } |
| 114 |
| 115 return A_OK; |
| 116 |
| 117 } |
| 118 |
| 119 static A_STATUS |
| 120 __HIFReadWrite(HIF_DEVICE *device, |
| 121 A_UINT32 address, |
| 122 A_UCHAR *buffer, |
| 123 A_UINT32 length, |
| 124 A_UINT32 request, |
| 125 void *context) |
| 126 { |
| 127 A_UINT8 opcode; |
| 128 A_STATUS status = A_OK; |
| 129 int ret; |
| 130 A_UINT8 *tbuffer; |
| 131 A_BOOL bounced = FALSE; |
| 132 |
| 133 AR_DEBUG_ASSERT(device != NULL); |
| 134 AR_DEBUG_ASSERT(device->func != NULL); |
| 135 |
| 136 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: 0x%p, buffer:0x%p (addr:0
x%X)\n", |
| 137 device, buffer, address)); |
| 138 |
| 139 do { |
| 140 if (request & HIF_EXTENDED_IO) { |
| 141 //AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Command type: CMD53\n")
); |
| 142 } else { |
| 143 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 144 ("AR6000: Invalid command type: 0x%08x\n", request))
; |
| 145 status = A_EINVAL; |
| 146 break; |
| 147 } |
| 148 |
| 149 if (request & HIF_BLOCK_BASIS) { |
| 150 /* round to whole block length size */ |
| 151 length = (length / HIF_MBOX_BLOCK_SIZE) * HIF_MBOX_BLOCK_SIZE; |
| 152 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, |
| 153 ("AR6000: Block mode (BlockLen: %d)\n", |
| 154 length)); |
| 155 } else if (request & HIF_BYTE_BASIS) { |
| 156 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, |
| 157 ("AR6000: Byte mode (BlockLen: %d)\n", |
| 158 length)); |
| 159 } else { |
| 160 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 161 ("AR6000: Invalid data mode: 0x%08x\n", request)); |
| 162 status = A_EINVAL; |
| 163 break; |
| 164 } |
| 165 |
| 166 #if 0 |
| 167 /* useful for checking register accesses */ |
| 168 if (length & 0x3) { |
| 169 A_PRINTF(KERN_ALERT"AR6000: HIF (%s) is not a multiple of 4 bytes, a
ddr:0x%X, len:%d\n", |
| 170 request & HIF_WRITE ? "write":"read", address, l
ength); |
| 171 } |
| 172 #endif |
| 173 |
| 174 if (request & HIF_WRITE) { |
| 175 if ((address >= HIF_MBOX_START_ADDR(0)) && |
| 176 (address <= HIF_MBOX_END_ADDR(3))) |
| 177 { |
| 178 |
| 179 AR_DEBUG_ASSERT(length <= HIF_MBOX_WIDTH); |
| 180 |
| 181 /* |
| 182 * Mailbox write. Adjust the address so that the last byte |
| 183 * falls on the EOM address. |
| 184 */ |
| 185 address += (HIF_MBOX_WIDTH - length); |
| 186 } |
| 187 } |
| 188 |
| 189 if (request & HIF_FIXED_ADDRESS) { |
| 190 opcode = CMD53_FIXED_ADDRESS; |
| 191 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Fixed 0x%X\
n", address)); |
| 192 } else if (request & HIF_INCREMENTAL_ADDRESS) { |
| 193 opcode = CMD53_INCR_ADDRESS; |
| 194 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Incremental
0x%X\n", address)); |
| 195 } else { |
| 196 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 197 ("AR6000: Invalid address mode: 0x%08x\n", request))
; |
| 198 status = A_EINVAL; |
| 199 break; |
| 200 } |
| 201 |
| 202 if (request & HIF_WRITE) { |
| 203 #if HIF_USE_DMA_BOUNCE_BUFFER |
| 204 if (BUFFER_NEEDS_BOUNCE(buffer)) { |
| 205 AR_DEBUG_ASSERT(device->dma_buffer != NULL); |
| 206 tbuffer = device->dma_buffer; |
| 207 /* copy the write data to the dma buffer */ |
| 208 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); |
| 209 memcpy(tbuffer, buffer, length); |
| 210 bounced = TRUE; |
| 211 } else { |
| 212 tbuffer = buffer; |
| 213 } |
| 214 #else |
| 215 tbuffer = buffer; |
| 216 #endif |
| 217 if (opcode == CMD53_FIXED_ADDRESS) { |
| 218 ret = sdio_writesb(device->func, address, tbuffer, length); |
| 219 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writesb ret=%d addres
s: 0x%X, len: %d, 0x%X\n", |
| 220 ret, address, length, *(int *)
tbuffer)); |
| 221 } else { |
| 222 ret = sdio_memcpy_toio(device->func, address, tbuffer, length); |
| 223 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writeio ret=%d addres
s: 0x%X, len: %d, 0x%X\n", |
| 224 ret, address, length, *(int *)
tbuffer)); |
| 225 } |
| 226 } else if (request & HIF_READ) { |
| 227 #if HIF_USE_DMA_BOUNCE_BUFFER |
| 228 if (BUFFER_NEEDS_BOUNCE(buffer)) { |
| 229 AR_DEBUG_ASSERT(device->dma_buffer != NULL); |
| 230 AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); |
| 231 tbuffer = device->dma_buffer; |
| 232 bounced = TRUE; |
| 233 } else { |
| 234 tbuffer = buffer; |
| 235 } |
| 236 #else |
| 237 tbuffer = buffer; |
| 238 #endif |
| 239 if (opcode == CMD53_FIXED_ADDRESS) { |
| 240 ret = sdio_readsb(device->func, tbuffer, address, length); |
| 241 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readsb ret=%d address
: 0x%X, len: %d, 0x%X\n", |
| 242 ret, address, length, *(int *)
tbuffer)); |
| 243 } else { |
| 244 ret = sdio_memcpy_fromio(device->func, tbuffer, address, length)
; |
| 245 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readio ret=%d address
: 0x%X, len: %d, 0x%X\n", |
| 246 ret, address, length, *(int *)
tbuffer)); |
| 247 } |
| 248 #if HIF_USE_DMA_BOUNCE_BUFFER |
| 249 if (bounced) { |
| 250 /* copy the read data from the dma buffer */ |
| 251 memcpy(buffer, tbuffer, length); |
| 252 } |
| 253 #endif |
| 254 } else { |
| 255 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 256 ("AR6000: Invalid direction: 0x%08x\n", request)); |
| 257 status = A_EINVAL; |
| 258 break; |
| 259 } |
| 260 |
| 261 if (ret) { |
| 262 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 263 ("AR6000: SDIO bus operation failed! MMC stack retur
ned : %d \n", ret)); |
| 264 status = A_ERROR; |
| 265 } |
| 266 } while (FALSE); |
| 267 |
| 268 return status; |
| 269 } |
| 270 |
| 271 /* queue a read/write request */ |
| 272 A_STATUS |
| 273 HIFReadWrite(HIF_DEVICE *device, |
| 274 A_UINT32 address, |
| 275 A_UCHAR *buffer, |
| 276 A_UINT32 length, |
| 277 A_UINT32 request, |
| 278 void *context) |
| 279 { |
| 280 A_STATUS status = A_OK; |
| 281 unsigned long flags; |
| 282 BUS_REQUEST *busrequest; |
| 283 BUS_REQUEST *async; |
| 284 BUS_REQUEST *active; |
| 285 |
| 286 AR_DEBUG_ASSERT(device != NULL); |
| 287 AR_DEBUG_ASSERT(device->func != NULL); |
| 288 |
| 289 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: %p addr:0x%X\n", device,a
ddress)); |
| 290 |
| 291 do { |
| 292 if ((request & HIF_ASYNCHRONOUS) || (request & HIF_SYNCHRONOUS)){ |
| 293 /* serialize all requests through the async thread */ |
| 294 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Execution mode: %s\n", |
| 295 (request & HIF_ASYNCHRONOUS)?"Async":"Synch")); |
| 296 busrequest = hifAllocateBusRequest(device); |
| 297 if (busrequest == NULL) { |
| 298 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 299 ("AR6000: no async bus requests available (%s, addr:0x%X, le
n:%d) \n", |
| 300 request & HIF_READ ? "READ":"WRITE", address, length)); |
| 301 return A_ERROR; |
| 302 } |
| 303 spin_lock_irqsave(&device->asynclock, flags); |
| 304 busrequest->address = address; |
| 305 busrequest->buffer = buffer; |
| 306 busrequest->length = length; |
| 307 busrequest->request = request; |
| 308 busrequest->context = context; |
| 309 /* add to async list */ |
| 310 active = device->asyncreq; |
| 311 if (active == NULL) { |
| 312 device->asyncreq = busrequest; |
| 313 device->asyncreq->inusenext = NULL; |
| 314 } else { |
| 315 for (async = device->asyncreq; |
| 316 async != NULL; |
| 317 async = async->inusenext) { |
| 318 active = async; |
| 319 } |
| 320 active->inusenext = busrequest; |
| 321 busrequest->inusenext = NULL; |
| 322 } |
| 323 spin_unlock_irqrestore(&device->asynclock, flags); |
| 324 if (request & HIF_SYNCHRONOUS) { |
| 325 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%X
\n", (unsigned int)busrequest)); |
| 326 |
| 327 /* wait for completion */ |
| 328 up(&device->sem_async); |
| 329 if (down_interruptible(&busrequest->sem_req) != 0) { |
| 330 /* interrupted, exit */ |
| 331 return A_ERROR; |
| 332 } else { |
| 333 A_STATUS status = busrequest->status; |
| 334 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freei
ng 0x%X: 0x%X\n", |
| 335 (unsigned int)busrequest,
busrequest->status)); |
| 336 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: freeing req: 0x%X
\n", (unsigned int)request)); |
| 337 hifFreeBusRequest(device, busrequest); |
| 338 return status; |
| 339 } |
| 340 } else { |
| 341 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%
X\n", (unsigned int)busrequest)); |
| 342 up(&device->sem_async); |
| 343 return A_PENDING; |
| 344 } |
| 345 } else { |
| 346 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, |
| 347 ("AR6000: Invalid execution mode: 0x%08x\n", (unsign
ed int)request)); |
| 348 status = A_EINVAL; |
| 349 break; |
| 350 } |
| 351 } while(0); |
| 352 |
| 353 return status; |
| 354 } |
| 355 /* thread to serialize all requests, both sync and async */ |
| 356 static int async_task(void *param) |
| 357 { |
| 358 HIF_DEVICE *device; |
| 359 BUS_REQUEST *request; |
| 360 A_STATUS status; |
| 361 unsigned long flags; |
| 362 |
| 363 device = (HIF_DEVICE *)param; |
| 364 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task\n")); |
| 365 set_current_state(TASK_INTERRUPTIBLE); |
| 366 while(!device->async_shutdown) { |
| 367 /* wait for work */ |
| 368 if (down_interruptible(&device->sem_async) != 0) { |
| 369 /* interrupted, exit */ |
| 370 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task interrupted\n"
)); |
| 371 break; |
| 372 } |
| 373 if (device->async_shutdown) { |
| 374 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task stopping\n")); |
| 375 break; |
| 376 } |
| 377 /* we want to hold the host over multiple cmds if possible, but holding
the host blocks card interrupts */ |
| 378 sdio_claim_host(device->func); |
| 379 spin_lock_irqsave(&device->asynclock, flags); |
| 380 /* pull the request to work on */ |
| 381 while (device->asyncreq != NULL) { |
| 382 request = device->asyncreq; |
| 383 if (request->inusenext != NULL) { |
| 384 device->asyncreq = request->inusenext; |
| 385 } else { |
| 386 device->asyncreq = NULL; |
| 387 } |
| 388 spin_unlock_irqrestore(&device->asynclock, flags); |
| 389 /* call HIFReadWrite in sync mode to do the work */ |
| 390 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task processing req
: 0x%X\n", (unsigned int)request)); |
| 391 status = __HIFReadWrite(device, request->address, request->buffer, |
| 392 request->length, request->request & ~HIF_SYNCH
RONOUS, NULL); |
| 393 if (request->request & HIF_ASYNCHRONOUS) { |
| 394 void *context = request->context; |
| 395 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task freeing re
q: 0x%X\n", (unsigned int)request)); |
| 396 hifFreeBusRequest(device, request); |
| 397 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task completion
routine req: 0x%X\n", (unsigned int)request)); |
| 398 device->htcCallbacks.rwCompletionHandler(context, status); |
| 399 } else { |
| 400 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task upping req
: 0x%X\n", (unsigned int)request)); |
| 401 request->status = status; |
| 402 up(&request->sem_req); |
| 403 } |
| 404 spin_lock_irqsave(&device->asynclock, flags); |
| 405 } |
| 406 spin_unlock_irqrestore(&device->asynclock, flags); |
| 407 sdio_release_host(device->func); |
| 408 } |
| 409 |
| 410 complete_and_exit(&device->async_completion, 0); |
| 411 return 0; |
| 412 } |
| 413 |
| 414 A_STATUS |
| 415 HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode, |
| 416 void *config, A_UINT32 configLen) |
| 417 { |
| 418 A_UINT32 count; |
| 419 |
| 420 switch(opcode) { |
| 421 case HIF_DEVICE_GET_MBOX_BLOCK_SIZE: |
| 422 ((A_UINT32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE; |
| 423 ((A_UINT32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE; |
| 424 ((A_UINT32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE; |
| 425 ((A_UINT32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE; |
| 426 break; |
| 427 |
| 428 case HIF_DEVICE_GET_MBOX_ADDR: |
| 429 for (count = 0; count < 4; count ++) { |
| 430 ((A_UINT32 *)config)[count] = HIF_MBOX_START_ADDR(count); |
| 431 } |
| 432 |
| 433 if (configLen >= sizeof(HIF_DEVICE_MBOX_INFO)) { |
| 434 SetExtendedMboxWindowInfo((A_UINT16)device->func->device, |
| 435 (HIF_DEVICE_MBOX_INFO *)config); |
| 436 } |
| 437 |
| 438 break; |
| 439 case HIF_DEVICE_GET_IRQ_PROC_MODE: |
| 440 *((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_SYNC_ON
LY; |
| 441 break; |
| 442 case HIF_DEVICE_GET_OS_DEVICE: |
| 443 /* pass back a pointer to the SDIO function's "dev" struct */ |
| 444 ((HIF_DEVICE_OS_DEVICE_INFO *)config)->pOSDevice = &device->func->de
v; |
| 445 break; |
| 446 default: |
| 447 AR_DEBUG_PRINTF(ATH_DEBUG_WARN, |
| 448 ("AR6000: Unsupported configuration opcode: %d\n", o
pcode)); |
| 449 return A_ERROR; |
| 450 } |
| 451 |
| 452 return A_OK; |
| 453 } |
| 454 |
| 455 void |
| 456 HIFShutDownDevice(HIF_DEVICE *device) |
| 457 { |
| 458 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +HIFShutDownDevice\n")); |
| 459 if (device != NULL) { |
| 460 AR_DEBUG_ASSERT(device->func != NULL); |
| 461 } else { |
| 462 /* since we are unloading the driver anyways, reset all cards in cas
e the SDIO card |
| 463 * is externally powered and we are unloading the SDIO stack. This
avoids the problem when |
| 464 * the SDIO stack is reloaded and attempts are made to re-enumerate
a card that is already |
| 465 * enumerated */ |
| 466 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFShutDownDevice, resetting\
n")); |
| 467 ResetAllCards(); |
| 468 |
| 469 /* Unregister with bus driver core */ |
| 470 if (registered) { |
| 471 registered = 0; |
| 472 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, |
| 473 ("AR6000: Unregistering with the bus driver\n")); |
| 474 sdio_unregister_driver(&ar6k_driver); |
| 475 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, |
| 476 ("AR6000: Unregistered\n")); |
| 477 } |
| 478 } |
| 479 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -HIFShutDownDevice\n")); |
| 480 } |
| 481 |
| 482 static void |
| 483 hifIRQHandler(struct sdio_func *func) |
| 484 { |
| 485 A_STATUS status; |
| 486 HIF_DEVICE *device; |
| 487 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifIRQHandler\n")); |
| 488 |
| 489 device = getHifDevice(func); |
| 490 /* release the host during ints so we can pick it back up when we process cm
ds */ |
| 491 sdio_release_host(device->func); |
| 492 status = device->htcCallbacks.dsrHandler(device->htcCallbacks.context); |
| 493 sdio_claim_host(device->func); |
| 494 AR_DEBUG_ASSERT(status == A_OK); |
| 495 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifIRQHandler\n")); |
| 496 } |
| 497 |
| 498 /* handle HTC startup via thread*/ |
| 499 static int startup_task(void *param) |
| 500 { |
| 501 HIF_DEVICE *device; |
| 502 |
| 503 device = (HIF_DEVICE *)param; |
| 504 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call HTC from startup_task\n")); |
| 505 /* start up inform DRV layer */ |
| 506 if ((osdrvCallbacks.deviceInsertedHandler(osdrvCallbacks.context,device)) !=
A_OK) { |
| 507 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n")); |
| 508 } |
| 509 return 0; |
| 510 } |
| 511 |
| 512 static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id
*id) |
| 513 { |
| 514 int ret; |
| 515 HIF_DEVICE * device; |
| 516 int count; |
| 517 struct task_struct* startup_task_struct; |
| 518 |
| 519 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, |
| 520 ("AR6000: hifDeviceInserted, Function: 0x%X, Vendor ID: 0x%X
, Device ID: 0x%X, block size: 0x%X/0x%X\n", |
| 521 func->num, func->vendor, func->device, func->max_blksize, f
unc->cur_blksize)); |
| 522 |
| 523 addHifDevice(func); |
| 524 device = getHifDevice(func); |
| 525 |
| 526 spin_lock_init(&device->lock); |
| 527 |
| 528 spin_lock_init(&device->asynclock); |
| 529 |
| 530 /* enable the SDIO function */ |
| 531 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: claim\n")); |
| 532 sdio_claim_host(func); |
| 533 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: enable\n")); |
| 534 /* give us some time to enable, in ms */ |
| 535 func->enable_timeout = 100; |
| 536 ret = sdio_enable_func(func); |
| 537 if (ret) { |
| 538 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K:
0x%X, timeout: %d\n", |
| 539 __FUNCTION__, ret, func->enable_timeou
t)); |
| 540 sdio_release_host(func); |
| 541 return ret; |
| 542 } |
| 543 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: set block size 0x%X\n", HIF_MBOX_
BLOCK_SIZE)); |
| 544 ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); |
| 545 sdio_release_host(func); |
| 546 if (ret) { |
| 547 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block siz
e 0x%x AR6K: 0x%X\n", |
| 548 __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret
)); |
| 549 sdio_release_host(func); |
| 550 return ret; |
| 551 } |
| 552 /* Initialize the bus requests to be used later */ |
| 553 A_MEMZERO(device->busRequest, sizeof(device->busRequest)); |
| 554 for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) { |
| 555 sema_init(&device->busRequest[count].sem_req, 0); |
| 556 hifFreeBusRequest(device, &device->busRequest[count]); |
| 557 } |
| 558 |
| 559 /* create async I/O thread */ |
| 560 device->async_shutdown = 0; |
| 561 device->async_task = kthread_create(async_task, |
| 562 (void *)device, |
| 563 "AR6K Async"); |
| 564 if (device->async_task == NULL) { |
| 565 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n"
, __FUNCTION__)); |
| 566 sdio_release_host(func); |
| 567 return A_ERROR; |
| 568 } |
| 569 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n")); |
| 570 sema_init(&device->sem_async, 0); |
| 571 wake_up_process(device->async_task ); |
| 572 |
| 573 /* create startup thread */ |
| 574 startup_task_struct = kthread_create(startup_task, |
| 575 (void *)device, |
| 576 "AR6K startup"); |
| 577 if (startup_task_struct == NULL) { |
| 578 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create startup task\
n", __FUNCTION__)); |
| 579 sdio_release_host(func); |
| 580 return A_ERROR; |
| 581 } |
| 582 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start startup task\n")); |
| 583 wake_up_process(startup_task_struct); |
| 584 |
| 585 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: return %d\n", ret)); |
| 586 return ret; |
| 587 } |
| 588 |
| 589 |
| 590 void |
| 591 HIFAckInterrupt(HIF_DEVICE *device) |
| 592 { |
| 593 AR_DEBUG_ASSERT(device != NULL); |
| 594 |
| 595 /* Acknowledge our function IRQ */ |
| 596 } |
| 597 |
| 598 void |
| 599 HIFUnMaskInterrupt(HIF_DEVICE *device) |
| 600 { |
| 601 int ret;; |
| 602 |
| 603 AR_DEBUG_ASSERT(device != NULL); |
| 604 AR_DEBUG_ASSERT(device->func != NULL); |
| 605 |
| 606 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFUnMaskInterrupt\n")); |
| 607 |
| 608 /* Register the IRQ Handler */ |
| 609 sdio_claim_host(device->func); |
| 610 ret = sdio_claim_irq(device->func, hifIRQHandler); |
| 611 sdio_release_host(device->func); |
| 612 AR_DEBUG_ASSERT(ret == 0); |
| 613 } |
| 614 |
| 615 void HIFMaskInterrupt(HIF_DEVICE *device) |
| 616 { |
| 617 int ret;; |
| 618 |
| 619 AR_DEBUG_ASSERT(device != NULL); |
| 620 AR_DEBUG_ASSERT(device->func != NULL); |
| 621 |
| 622 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFMaskInterrupt\n")); |
| 623 |
| 624 /* Mask our function IRQ */ |
| 625 sdio_claim_host(device->func); |
| 626 ret = sdio_release_irq(device->func); |
| 627 sdio_release_host(device->func); |
| 628 AR_DEBUG_ASSERT(ret == 0); |
| 629 } |
| 630 |
| 631 static BUS_REQUEST *hifAllocateBusRequest(HIF_DEVICE *device) |
| 632 { |
| 633 BUS_REQUEST *busrequest; |
| 634 unsigned long flag; |
| 635 |
| 636 /* Acquire lock */ |
| 637 spin_lock_irqsave(&device->lock, flag); |
| 638 |
| 639 /* Remove first in list */ |
| 640 if((busrequest = device->s_busRequestFreeQueue) != NULL) |
| 641 { |
| 642 device->s_busRequestFreeQueue = busrequest->next; |
| 643 } |
| 644 |
| 645 /* Release lock */ |
| 646 spin_unlock_irqrestore(&device->lock, flag); |
| 647 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifAllocateBusRequest: 0x%p\n", b
usrequest)); |
| 648 return busrequest; |
| 649 } |
| 650 |
| 651 static void |
| 652 hifFreeBusRequest(HIF_DEVICE *device, BUS_REQUEST *busrequest) |
| 653 { |
| 654 unsigned long flag; |
| 655 |
| 656 AR_DEBUG_ASSERT(busrequest != NULL); |
| 657 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifFreeBusRequest: 0x%p\n", busre
quest)); |
| 658 /* Acquire lock */ |
| 659 spin_lock_irqsave(&device->lock, flag); |
| 660 |
| 661 |
| 662 /* Insert first in list */ |
| 663 busrequest->next = device->s_busRequestFreeQueue; |
| 664 busrequest->inusenext = NULL; |
| 665 device->s_busRequestFreeQueue = busrequest; |
| 666 |
| 667 /* Release lock */ |
| 668 spin_unlock_irqrestore(&device->lock, flag); |
| 669 } |
| 670 |
| 671 static void hifDeviceRemoved(struct sdio_func *func) |
| 672 { |
| 673 A_STATUS status = A_OK; |
| 674 HIF_DEVICE *device; |
| 675 int ret; |
| 676 AR_DEBUG_ASSERT(func != NULL); |
| 677 |
| 678 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceRemoved\n")); |
| 679 device = getHifDevice(func); |
| 680 if (device->claimedContext != NULL) { |
| 681 status = osdrvCallbacks.deviceRemovedHandler(device->claimedContext, dev
ice); |
| 682 } |
| 683 |
| 684 if (device->async_task != NULL) { |
| 685 init_completion(&device->async_completion); |
| 686 device->async_shutdown = 1; |
| 687 up(&device->sem_async); |
| 688 wait_for_completion(&device->async_completion); |
| 689 device->async_task = NULL; |
| 690 } |
| 691 /* Disable the card */ |
| 692 sdio_claim_host(device->func); |
| 693 ret = sdio_disable_func(device->func); |
| 694 |
| 695 if (reset_sdio_on_unload) { |
| 696 int ret; |
| 697 /* reset the SDIO interface. This is useful in automated testing where
the card |
| 698 * does not need to be removed at the end of the test. It is expected t
hat the user will |
| 699 * also unload/reload the host controller driver to force the bus driver
to re-enumerate the slot */ |
| 700 AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6000: reseting SDIO card back to uni
nitialized state \n")); |
| 701 |
| 702 /* NOTE : sdio_f0_writeb() cannot be used here, that API only allows acc
ess |
| 703 * to undefined registers in the range of: 0xF0-0xFF */ |
| 704 |
| 705 ret = Func0_CMD52WriteByte(device->func->card, SDIO_CCCR_ABORT, (1 << 3)
); |
| 706 if (ret) { |
| 707 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret)
); |
| 708 } |
| 709 } |
| 710 |
| 711 sdio_release_host(device->func); |
| 712 delHifDevice(device); |
| 713 AR_DEBUG_ASSERT(status == A_OK); |
| 714 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceRemoved\n")); |
| 715 } |
| 716 |
| 717 |
| 718 static HIF_DEVICE * |
| 719 addHifDevice(struct sdio_func *func) |
| 720 { |
| 721 HIF_DEVICE *hifdevice; |
| 722 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: addHifDevice\n")); |
| 723 AR_DEBUG_ASSERT(func != NULL); |
| 724 hifdevice = (HIF_DEVICE *)kzalloc(sizeof(HIF_DEVICE), GFP_KERNEL); |
| 725 AR_DEBUG_ASSERT(hifdevice != NULL); |
| 726 #if HIF_USE_DMA_BOUNCE_BUFFER |
| 727 hifdevice->dma_buffer = kmalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); |
| 728 AR_DEBUG_ASSERT(hifdevice->dma_buffer != NULL); |
| 729 #endif |
| 730 hifdevice->func = func; |
| 731 sdio_set_drvdata(func, hifdevice); |
| 732 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: addHifDevice; 0x%p\n", hifdevice)
); |
| 733 return hifdevice; |
| 734 } |
| 735 |
| 736 static HIF_DEVICE * |
| 737 getHifDevice(struct sdio_func *func) |
| 738 { |
| 739 AR_DEBUG_ASSERT(func != NULL); |
| 740 return (HIF_DEVICE *)sdio_get_drvdata(func); |
| 741 } |
| 742 |
| 743 static void |
| 744 delHifDevice(HIF_DEVICE * device) |
| 745 { |
| 746 AR_DEBUG_ASSERT(device!= NULL); |
| 747 AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: delHifDevice; 0x%p\n", device)); |
| 748 if (device->dma_buffer != NULL) { |
| 749 kfree(device->dma_buffer); |
| 750 } |
| 751 kfree(device); |
| 752 } |
| 753 |
| 754 static void ResetAllCards(void) |
| 755 { |
| 756 } |
| 757 |
| 758 void HIFClaimDevice(HIF_DEVICE *device, void *context) |
| 759 { |
| 760 device->claimedContext = context; |
| 761 } |
| 762 |
| 763 void HIFReleaseDevice(HIF_DEVICE *device) |
| 764 { |
| 765 device->claimedContext = NULL; |
| 766 } |
| 767 |
| 768 A_STATUS HIFAttachHTC(HIF_DEVICE *device, HTC_CALLBACKS *callbacks) |
| 769 { |
| 770 if (device->htcCallbacks.context != NULL) { |
| 771 /* already in use! */ |
| 772 return A_ERROR; |
| 773 } |
| 774 device->htcCallbacks = *callbacks; |
| 775 return A_OK; |
| 776 } |
| 777 |
| 778 void HIFDetachHTC(HIF_DEVICE *device) |
| 779 { |
| 780 A_MEMZERO(&device->htcCallbacks,sizeof(device->htcCallbacks)); |
| 781 } |
| 782 |
| 783 #define SDIO_SET_CMD52_ARG(arg,rw,func,raw,address,writedata) \ |
| 784 (arg) = (((rw) & 1) << 31) | \ |
| 785 (((func) & 0x7) << 28) | \ |
| 786 (((raw) & 1) << 27) | \ |
| 787 (1 << 26) | \ |
| 788 (((address) & 0x1FFFF) << 9) | \ |
| 789 (1 << 8) | \ |
| 790 ((writedata) & 0xFF) |
| 791 |
| 792 #define SDIO_SET_CMD52_READ_ARG(arg,func,address) \ |
| 793 SDIO_SET_CMD52_ARG(arg,0,(func),0,address,0x00) |
| 794 #define SDIO_SET_CMD52_WRITE_ARG(arg,func,address,value) \ |
| 795 SDIO_SET_CMD52_ARG(arg,1,(func),0,address,value) |
| 796 |
| 797 static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, uns
igned char byte) |
| 798 { |
| 799 struct mmc_command ioCmd; |
| 800 unsigned long arg; |
| 801 |
| 802 memset(&ioCmd,0,sizeof(ioCmd)); |
| 803 SDIO_SET_CMD52_WRITE_ARG(arg,0,address,byte); |
| 804 ioCmd.opcode = SD_IO_RW_DIRECT; |
| 805 ioCmd.arg = arg; |
| 806 ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC; |
| 807 |
| 808 return mmc_wait_for_cmd(card->host, &ioCmd, 0); |
| 809 } |
| 810 |
| 811 |
| 812 |
| 813 |
OLD | NEW |