diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-21 08:36:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-29 18:03:56 -0400 |
commit | 177bc7dade38b5bd02dbcd008f92135b2c7a92b6 (patch) | |
tree | 7d7992fad74944f5d479193abea666e39338b439 /drivers/media/dvb | |
parent | b37d2a3a75cb0e72e18c29336cb2095b63dabfc8 (diff) |
[media] drxk: change it to use request_firmware_nowait()
The firmware blob may not be available when the driver probes.
Instead of blocking the whole kernel use request_firmware_nowait() and
continue without firmware.
This shouldn't be that bad on drx-k devices, as they all seem to have an
internal firmware. So, only the firmware update will take a little longer
to happen.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r-- | drivers/media/dvb/frontends/drxk_hard.c | 109 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/drxk_hard.h | 3 |
2 files changed, 72 insertions, 40 deletions
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index 60b868faeac..4cb8d1e83fb 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c | |||
@@ -5968,29 +5968,9 @@ error: | |||
5968 | return status; | 5968 | return status; |
5969 | } | 5969 | } |
5970 | 5970 | ||
5971 | static int load_microcode(struct drxk_state *state, const char *mc_name) | ||
5972 | { | ||
5973 | const struct firmware *fw = NULL; | ||
5974 | int err = 0; | ||
5975 | |||
5976 | dprintk(1, "\n"); | ||
5977 | |||
5978 | err = request_firmware(&fw, mc_name, state->i2c->dev.parent); | ||
5979 | if (err < 0) { | ||
5980 | printk(KERN_ERR | ||
5981 | "drxk: Could not load firmware file %s.\n", mc_name); | ||
5982 | printk(KERN_INFO | ||
5983 | "drxk: Copy %s to your hotplug directory!\n", mc_name); | ||
5984 | return err; | ||
5985 | } | ||
5986 | err = DownloadMicrocode(state, fw->data, fw->size); | ||
5987 | release_firmware(fw); | ||
5988 | return err; | ||
5989 | } | ||
5990 | |||
5991 | static int init_drxk(struct drxk_state *state) | 5971 | static int init_drxk(struct drxk_state *state) |
5992 | { | 5972 | { |
5993 | int status = 0; | 5973 | int status = 0, n = 0; |
5994 | enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; | 5974 | enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; |
5995 | u16 driverVersion; | 5975 | u16 driverVersion; |
5996 | 5976 | ||
@@ -6073,8 +6053,12 @@ static int init_drxk(struct drxk_state *state) | |||
6073 | if (status < 0) | 6053 | if (status < 0) |
6074 | goto error; | 6054 | goto error; |
6075 | 6055 | ||
6076 | if (state->microcode_name) | 6056 | if (state->fw) { |
6077 | load_microcode(state, state->microcode_name); | 6057 | status = DownloadMicrocode(state, state->fw->data, |
6058 | state->fw->size); | ||
6059 | if (status < 0) | ||
6060 | goto error; | ||
6061 | } | ||
6078 | 6062 | ||
6079 | /* disable token-ring bus through OFDM block for possible ucode upload */ | 6063 | /* disable token-ring bus through OFDM block for possible ucode upload */ |
6080 | status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF); | 6064 | status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF); |
@@ -6167,6 +6151,20 @@ static int init_drxk(struct drxk_state *state) | |||
6167 | state->m_DrxkState = DRXK_POWERED_DOWN; | 6151 | state->m_DrxkState = DRXK_POWERED_DOWN; |
6168 | } else | 6152 | } else |
6169 | state->m_DrxkState = DRXK_STOPPED; | 6153 | state->m_DrxkState = DRXK_STOPPED; |
6154 | |||
6155 | /* Initialize the supported delivery systems */ | ||
6156 | n = 0; | ||
6157 | if (state->m_hasDVBC) { | ||
6158 | state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; | ||
6159 | state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; | ||
6160 | strlcat(state->frontend.ops.info.name, " DVB-C", | ||
6161 | sizeof(state->frontend.ops.info.name)); | ||
6162 | } | ||
6163 | if (state->m_hasDVBT) { | ||
6164 | state->frontend.ops.delsys[n++] = SYS_DVBT; | ||
6165 | strlcat(state->frontend.ops.info.name, " DVB-T", | ||
6166 | sizeof(state->frontend.ops.info.name)); | ||
6167 | } | ||
6170 | } | 6168 | } |
6171 | error: | 6169 | error: |
6172 | if (status < 0) | 6170 | if (status < 0) |
@@ -6175,11 +6173,44 @@ error: | |||
6175 | return status; | 6173 | return status; |
6176 | } | 6174 | } |
6177 | 6175 | ||
6176 | static void load_firmware_cb(const struct firmware *fw, | ||
6177 | void *context) | ||
6178 | { | ||
6179 | struct drxk_state *state = context; | ||
6180 | |||
6181 | if (!fw) { | ||
6182 | printk(KERN_ERR | ||
6183 | "drxk: Could not load firmware file %s.\n", | ||
6184 | state->microcode_name); | ||
6185 | printk(KERN_INFO | ||
6186 | "drxk: Copy %s to your hotplug directory!\n", | ||
6187 | state->microcode_name); | ||
6188 | state->microcode_name = NULL; | ||
6189 | |||
6190 | /* | ||
6191 | * As firmware is now load asynchronous, it is not possible | ||
6192 | * anymore to fail at frontend attach. We might silently | ||
6193 | * return here, and hope that the driver won't crash. | ||
6194 | * We might also change all DVB callbacks to return -ENODEV | ||
6195 | * if the device is not initialized. | ||
6196 | * As the DRX-K devices have their own internal firmware, | ||
6197 | * let's just hope that it will match a firmware revision | ||
6198 | * compatible with this driver and proceed. | ||
6199 | */ | ||
6200 | } | ||
6201 | state->fw = fw; | ||
6202 | |||
6203 | init_drxk(state); | ||
6204 | } | ||
6205 | |||
6178 | static void drxk_release(struct dvb_frontend *fe) | 6206 | static void drxk_release(struct dvb_frontend *fe) |
6179 | { | 6207 | { |
6180 | struct drxk_state *state = fe->demodulator_priv; | 6208 | struct drxk_state *state = fe->demodulator_priv; |
6181 | 6209 | ||
6182 | dprintk(1, "\n"); | 6210 | dprintk(1, "\n"); |
6211 | if (state->fw) | ||
6212 | release_firmware(state->fw); | ||
6213 | |||
6183 | kfree(state); | 6214 | kfree(state); |
6184 | } | 6215 | } |
6185 | 6216 | ||
@@ -6371,10 +6402,9 @@ static struct dvb_frontend_ops drxk_ops = { | |||
6371 | struct dvb_frontend *drxk_attach(const struct drxk_config *config, | 6402 | struct dvb_frontend *drxk_attach(const struct drxk_config *config, |
6372 | struct i2c_adapter *i2c) | 6403 | struct i2c_adapter *i2c) |
6373 | { | 6404 | { |
6374 | int n; | ||
6375 | |||
6376 | struct drxk_state *state = NULL; | 6405 | struct drxk_state *state = NULL; |
6377 | u8 adr = config->adr; | 6406 | u8 adr = config->adr; |
6407 | int status; | ||
6378 | 6408 | ||
6379 | dprintk(1, "\n"); | 6409 | dprintk(1, "\n"); |
6380 | state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL); | 6410 | state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL); |
@@ -6425,22 +6455,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, | |||
6425 | state->frontend.demodulator_priv = state; | 6455 | state->frontend.demodulator_priv = state; |
6426 | 6456 | ||
6427 | init_state(state); | 6457 | init_state(state); |
6428 | if (init_drxk(state) < 0) | ||
6429 | goto error; | ||
6430 | 6458 | ||
6431 | /* Initialize the supported delivery systems */ | 6459 | /* Load firmware and initialize DRX-K */ |
6432 | n = 0; | 6460 | if (state->microcode_name) { |
6433 | if (state->m_hasDVBC) { | 6461 | status = request_firmware_nowait(THIS_MODULE, 1, |
6434 | state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; | 6462 | state->microcode_name, |
6435 | state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; | 6463 | state->i2c->dev.parent, |
6436 | strlcat(state->frontend.ops.info.name, " DVB-C", | 6464 | GFP_KERNEL, |
6437 | sizeof(state->frontend.ops.info.name)); | 6465 | state, load_firmware_cb); |
6438 | } | 6466 | if (status < 0) { |
6439 | if (state->m_hasDVBT) { | 6467 | printk(KERN_ERR |
6440 | state->frontend.ops.delsys[n++] = SYS_DVBT; | 6468 | "drxk: failed to request a firmware\n"); |
6441 | strlcat(state->frontend.ops.info.name, " DVB-T", | 6469 | return NULL; |
6442 | sizeof(state->frontend.ops.info.name)); | 6470 | } |
6443 | } | 6471 | } else if (init_drxk(state) < 0) |
6472 | goto error; | ||
6444 | 6473 | ||
6445 | printk(KERN_INFO "drxk: frontend initialized.\n"); | 6474 | printk(KERN_INFO "drxk: frontend initialized.\n"); |
6446 | return &state->frontend; | 6475 | return &state->frontend; |
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h index 4bbf841de83..36677cdc01d 100644 --- a/drivers/media/dvb/frontends/drxk_hard.h +++ b/drivers/media/dvb/frontends/drxk_hard.h | |||
@@ -338,7 +338,10 @@ struct drxk_state { | |||
338 | bool antenna_dvbt; | 338 | bool antenna_dvbt; |
339 | u16 antenna_gpio; | 339 | u16 antenna_gpio; |
340 | 340 | ||
341 | /* Firmware */ | ||
341 | const char *microcode_name; | 342 | const char *microcode_name; |
343 | struct completion fw_wait_load; | ||
344 | const struct firmware *fw; | ||
342 | }; | 345 | }; |
343 | 346 | ||
344 | #define NEVER_LOCK 0 | 347 | #define NEVER_LOCK 0 |