FILE
sdio_intf.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
1// SPDX-License-Identifier: GPL-2.0 2/****************************************************************************** 3 * 4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 5 * 6 ******************************************************************************/ 7#include <drv_types.h> 8#include <hal_btcoex.h> 9#include <linux/jiffies.h> 10 11#ifndef dev_to_sdio_func 12#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) 13#endif 14 15static const struct sdio_device_id sdio_ids[] = { 16 { SDIO_DEVICE(0x024c, 0x0523), }, 17 { SDIO_DEVICE(0x024c, 0x0525), }, 18 { SDIO_DEVICE(0x024c, 0x0623), }, 19 { SDIO_DEVICE(0x024c, 0x0626), }, 20 { SDIO_DEVICE(0x024c, 0x0627), }, 21 { SDIO_DEVICE(0x024c, 0xb723), }, 22 { /* end: all zeroes */ }, 23}; 24MODULE_DEVICE_TABLE(sdio, sdio_ids); 25 26static int rtw_drv_init(struct sdio_func *func, const struct sdio_device_id *id); 27static void rtw_dev_remove(struct sdio_func *func); 28static int rtw_sdio_resume(struct device *dev); 29static int rtw_sdio_suspend(struct device *dev); 30 31static const struct dev_pm_ops rtw_sdio_pm_ops = { 32 .suspend = rtw_sdio_suspend, 33 .resume = rtw_sdio_resume, 34}; 35 36static struct sdio_driver rtl8723bs_sdio_driver = { 37 .probe = rtw_drv_init, 38 .remove = rtw_dev_remove, 39 .name = "rtl8723bs", 40 .id_table = sdio_ids, 41 .drv = { 42 .pm = &rtw_sdio_pm_ops, 43 } 44}; 45 46static void sd_sync_int_hdl(struct sdio_func *func) 47{ 48 struct dvobj_priv *psdpriv; 49 50 51 psdpriv = sdio_get_drvdata(func); 52 53 if (!psdpriv->if1) 54 return; 55 56 rtw_sdio_set_irq_thd(psdpriv, current); 57 sd_int_hdl(psdpriv->if1); 58 rtw_sdio_set_irq_thd(psdpriv, NULL); 59} 60 61static int sdio_alloc_irq(struct dvobj_priv *dvobj) 62{ 63 struct sdio_data *psdio_data; 64 struct sdio_func *func; 65 int err; 66 67 psdio_data = &dvobj->intf_data; 68 func = psdio_data->func; 69 70 sdio_claim_host(func); 71 72 err = sdio_claim_irq(func, &sd_sync_int_hdl); 73 if (err) { 74 dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++; 75 netdev_crit(dvobj->if1->pnetdev, "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err); 76 } else { 77 dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++; 78 dvobj->irq_alloc = 1; 79 } 80 81 sdio_release_host(func); 82 83 return err?_FAIL:_SUCCESS; 84} 85 86static void sdio_free_irq(struct dvobj_priv *dvobj) 87{ 88 struct sdio_data *psdio_data; 89 struct sdio_func *func; 90 int err; 91 92 if (dvobj->irq_alloc) { 93 psdio_data = &dvobj->intf_data; 94 func = psdio_data->func; 95 96 if (func) { 97 sdio_claim_host(func); 98 err = sdio_release_irq(func); 99 if (err) { 100 dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; 101 netdev_err(dvobj->if1->pnetdev, 102 "%s: sdio_release_irq FAIL(%d)!\n", 103 __func__, err); 104 } else 105 dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; 106 sdio_release_host(func); 107 } 108 dvobj->irq_alloc = 0; 109 } 110} 111 112static u32 sdio_init(struct dvobj_priv *dvobj) 113{ 114 struct sdio_data *psdio_data; 115 struct sdio_func *func; 116 int err; 117 118 psdio_data = &dvobj->intf_data; 119 func = psdio_data->func; 120 121 /* 3 1. init SDIO bus */ 122 sdio_claim_host(func); 123 124 err = sdio_enable_func(func); 125 if (err) { 126 dvobj->drv_dbg.dbg_sdio_init_error_cnt++; 127 goto release; 128 } 129 130 err = sdio_set_block_size(func, 512); 131 if (err) { 132 dvobj->drv_dbg.dbg_sdio_init_error_cnt++; 133 goto release; 134 } 135 psdio_data->block_transfer_len = 512; 136 psdio_data->tx_block_mode = 1; 137 psdio_data->rx_block_mode = 1; 138 139release: 140 sdio_release_host(func); 141 142 if (err) 143 return _FAIL; 144 return _SUCCESS; 145} 146 147static void sdio_deinit(struct dvobj_priv *dvobj) 148{ 149 struct sdio_func *func; 150 int err; 151 152 func = dvobj->intf_data.func; 153 154 if (func) { 155 sdio_claim_host(func); 156 err = sdio_disable_func(func); 157 if (err) 158 dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++; 159 160 if (dvobj->irq_alloc) { 161 err = sdio_release_irq(func); 162 if (err) 163 dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++; 164 else 165 dvobj->drv_dbg.dbg_sdio_free_irq_cnt++; 166 } 167 168 sdio_release_host(func); 169 } 170} 171static struct dvobj_priv *sdio_dvobj_init(struct sdio_func *func) 172{ 173 int status = _FAIL; 174 struct dvobj_priv *dvobj = NULL; 175 struct sdio_data *psdio; 176 177 dvobj = devobj_init(); 178 if (!dvobj) 179 goto exit; 180 181 sdio_set_drvdata(func, dvobj); 182 183 psdio = &dvobj->intf_data; 184 psdio->func = func; 185 186 if (sdio_init(dvobj) != _SUCCESS) 187 goto free_dvobj; 188 189 rtw_reset_continual_io_error(dvobj); 190 status = _SUCCESS; 191 192free_dvobj: 193 if (status != _SUCCESS && dvobj) { 194 sdio_set_drvdata(func, NULL); 195 196 devobj_deinit(dvobj); 197 198 dvobj = NULL; 199 } 200exit: 201 return dvobj; 202} 203 204static void sdio_dvobj_deinit(struct sdio_func *func) 205{ 206 struct dvobj_priv *dvobj = sdio_get_drvdata(func); 207 208 sdio_set_drvdata(func, NULL); 209 if (dvobj) { 210 sdio_deinit(dvobj); 211 devobj_deinit(dvobj); 212 } 213} 214 215void rtw_set_hal_ops(struct adapter *padapter) 216{ 217 /* alloc memory for HAL DATA */ 218 rtw_hal_data_init(padapter); 219} 220 221static void sd_intf_start(struct adapter *padapter) 222{ 223 if (!padapter) 224 return; 225 226 /* hal dep */ 227 rtw_hal_enable_interrupt(padapter); 228} 229 230static void sd_intf_stop(struct adapter *padapter) 231{ 232 if (!padapter) 233 return; 234 235 /* hal dep */ 236 rtw_hal_disable_interrupt(padapter); 237} 238 239 240static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct sdio_device_id *pdid) 241{ 242 int status = _FAIL; 243 struct net_device *pnetdev; 244 struct adapter *padapter = NULL; 245 struct sdio_data *psdio = &dvobj->intf_data; 246 247 padapter = vzalloc(sizeof(*padapter)); 248 if (!padapter) 249 goto exit; 250 251 padapter->dvobj = dvobj; 252 dvobj->if1 = padapter; 253 254 padapter->bDriverStopped = true; 255 256 dvobj->padapters = padapter; 257 padapter->iface_id = 0; 258 259 /* 3 1. init network device data */ 260 pnetdev = rtw_init_netdev(padapter); 261 if (!pnetdev) 262 goto free_adapter; 263 264 SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); 265 266 padapter = rtw_netdev_priv(pnetdev); 267 268 /* 3 3. init driver special setting, interface, OS and hardware relative */ 269 270 /* 4 3.1 set hardware operation functions */ 271 rtw_set_hal_ops(padapter); 272 273 274 /* 3 5. initialize Chip version */ 275 padapter->intf_start = &sd_intf_start; 276 padapter->intf_stop = &sd_intf_stop; 277 278 padapter->intf_init = &sdio_init; 279 padapter->intf_deinit = &sdio_deinit; 280 padapter->intf_alloc_irq = &sdio_alloc_irq; 281 padapter->intf_free_irq = &sdio_free_irq; 282 283 if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) 284 goto free_hal_data; 285 286 rtw_hal_read_chip_version(padapter); 287 288 rtw_hal_chip_configure(padapter); 289 290 hal_btcoex_Initialize((void *)padapter); 291 292 /* 3 6. read efuse/eeprom data */ 293 rtw_hal_read_chip_info(padapter); 294 295 /* 3 7. init driver common data */ 296 if (rtw_init_drv_sw(padapter) == _FAIL) 297 goto free_hal_data; 298 299 rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); 300 301 /* 3 8. get WLan MAC address */ 302 /* set mac addr */ 303 rtw_macaddr_cfg(&psdio->func->dev, padapter->eeprompriv.mac_addr); 304 305 rtw_hal_disable_interrupt(padapter); 306 307 status = _SUCCESS; 308 309free_hal_data: 310 if (status != _SUCCESS && padapter->HalData) 311 kfree(padapter->HalData); 312 313 if (status != _SUCCESS) { 314 rtw_wdev_unregister(padapter->rtw_wdev); 315 rtw_wdev_free(padapter->rtw_wdev); 316 } 317 318free_adapter: 319 if (status != _SUCCESS) { 320 if (pnetdev) 321 rtw_free_netdev(pnetdev); 322 else 323 vfree((u8 *)padapter); 324 padapter = NULL; 325 } 326exit: 327 return padapter; 328} 329 330static void rtw_sdio_if1_deinit(struct adapter *if1) 331{ 332 struct net_device *pnetdev = if1->pnetdev; 333 struct mlme_priv *pmlmepriv = &if1->mlmepriv; 334 335 if (check_fwstate(pmlmepriv, _FW_LINKED)) 336 rtw_disassoc_cmd(if1, 0, false); 337 338 free_mlme_ap_info(if1); 339 340 rtw_cancel_all_timer(if1); 341 342 rtw_dev_unload(if1); 343 344 if (if1->rtw_wdev) 345 rtw_wdev_free(if1->rtw_wdev); 346 347 rtw_free_drv_sw(if1); 348 349 if (pnetdev) 350 rtw_free_netdev(pnetdev); 351} 352 353/* 354 * drv_init() - a device potentially for us 355 * 356 * notes: drv_init() is called when the bus driver has located a card for us to support. 357 * We accept the new device by returning 0. 358 */ 359static int rtw_drv_init( 360 struct sdio_func *func, 361 const struct sdio_device_id *id) 362{ 363 int status = _FAIL; 364 struct adapter *if1 = NULL; 365 struct dvobj_priv *dvobj; 366 367 dvobj = sdio_dvobj_init(func); 368 if (!dvobj) 369 goto exit; 370 371 if1 = rtw_sdio_if1_init(dvobj, id); 372 if (!if1) 373 goto free_dvobj; 374 375 /* dev_alloc_name && register_netdev */ 376 status = rtw_drv_register_netdev(if1); 377 if (status != _SUCCESS) 378 goto free_if1; 379 380 status = sdio_alloc_irq(dvobj); 381 if (status != _SUCCESS) 382 goto free_if1; 383 384 status = _SUCCESS; 385 386free_if1: 387 if (status != _SUCCESS && if1) 388 rtw_sdio_if1_deinit(if1); 389 390free_dvobj: 391 if (status != _SUCCESS) 392 sdio_dvobj_deinit(func); 393exit: 394 return status == _SUCCESS ? 0 : -ENODEV; 395} 396 397static void rtw_dev_remove(struct sdio_func *func) 398{ 399 struct dvobj_priv *dvobj = sdio_get_drvdata(func); 400 struct adapter *padapter = dvobj->if1; 401 402 dvobj->processing_dev_remove = true; 403 404 rtw_unregister_netdevs(dvobj); 405 406 if (!padapter->bSurpriseRemoved) { 407 int err; 408 409 /* test surprise remove */ 410 sdio_claim_host(func); 411 sdio_readb(func, 0, &err); 412 sdio_release_host(func); 413 if (err == -ENOMEDIUM) 414 padapter->bSurpriseRemoved = true; 415 } 416 417 rtw_ps_deny(padapter, PS_DENY_DRV_REMOVE); 418 419 rtw_pm_set_ips(padapter, IPS_NONE); 420 rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); 421 422 LeaveAllPowerSaveMode(padapter); 423 424 rtw_btcoex_HaltNotify(padapter); 425 426 rtw_sdio_if1_deinit(padapter); 427 428 sdio_dvobj_deinit(func); 429} 430 431static int rtw_sdio_suspend(struct device *dev) 432{ 433 struct sdio_func *func = dev_to_sdio_func(dev); 434 struct dvobj_priv *psdpriv = sdio_get_drvdata(func); 435 struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv); 436 struct adapter *padapter = psdpriv->if1; 437 struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; 438 439 if (padapter->bDriverStopped) 440 return 0; 441 442 if (pwrpriv->bInSuspend) { 443 pdbgpriv->dbg_suspend_error_cnt++; 444 return 0; 445 } 446 447 rtw_suspend_common(padapter); 448 449 return 0; 450} 451 452static int rtw_resume_process(struct adapter *padapter) 453{ 454 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 455 struct dvobj_priv *psdpriv = padapter->dvobj; 456 struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; 457 458 if (!pwrpriv->bInSuspend) { 459 pdbgpriv->dbg_resume_error_cnt++; 460 return -1; 461 } 462 463 return rtw_resume_common(padapter); 464} 465 466static int rtw_sdio_resume(struct device *dev) 467{ 468 struct sdio_func *func = dev_to_sdio_func(dev); 469 struct dvobj_priv *psdpriv = sdio_get_drvdata(func); 470 struct adapter *padapter = psdpriv->if1; 471 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 472 int ret = 0; 473 struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; 474 475 pdbgpriv->dbg_resume_cnt++; 476 477 ret = rtw_resume_process(padapter); 478 479 pmlmeext->last_scan_time = jiffies; 480 return ret; 481} 482 483static int __init rtw_drv_entry(void) 484{ 485 return sdio_register_driver(&rtl8723bs_sdio_driver); 486} 487module_init(rtw_drv_entry); 488 489static void __exit rtw_drv_halt(void) 490{ 491 sdio_unregister_driver(&rtl8723bs_sdio_driver); 492} 493module_exit(rtw_drv_halt); 494 495MODULE_DESCRIPTION("Realtek RTL8723BS SDIO WiFi driver");
~/
Read-only file preview.