Skip to content

Commit ac7e083

Browse files
committed
Input: ili210x - switch to using cleanup functions in firmware code
Start using __free() attributes to simplify the code and error handling. Link: https://lore.kernel.org/r/20240609234757.610273-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
1 parent 17f5eeb commit ac7e083

1 file changed

Lines changed: 63 additions & 60 deletions

File tree

drivers/input/touchscreen/ili210x.c

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -582,35 +582,31 @@ static ssize_t ili210x_calibrate(struct device *dev,
582582
}
583583
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
584584

585-
static int ili251x_firmware_to_buffer(const struct firmware *fw,
586-
u8 **buf, u16 *ac_end, u16 *df_end)
585+
static const u8 *ili251x_firmware_to_buffer(const struct firmware *fw,
586+
u16 *ac_end, u16 *df_end)
587587
{
588588
const struct ihex_binrec *rec;
589589
u32 fw_addr, fw_last_addr = 0;
590590
u16 fw_len;
591-
u8 *fw_buf;
592-
int error;
593591

594592
/*
595593
* The firmware ihex blob can never be bigger than 64 kiB, so make this
596594
* simple -- allocate a 64 kiB buffer, iterate over the ihex blob records
597595
* once, copy them all into this buffer at the right locations, and then
598596
* do all operations on this linear buffer.
599597
*/
600-
fw_buf = kvmalloc(SZ_64K, GFP_KERNEL);
598+
u8* fw_buf __free(kvfree) = kvmalloc(SZ_64K, GFP_KERNEL);
601599
if (!fw_buf)
602-
return -ENOMEM;
600+
return ERR_PTR(-ENOMEM);
603601

604602
rec = (const struct ihex_binrec *)fw->data;
605603
while (rec) {
606604
fw_addr = be32_to_cpu(rec->addr);
607605
fw_len = be16_to_cpu(rec->len);
608606

609607
/* The last 32 Byte firmware block can be 0xffe0 */
610-
if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32) {
611-
error = -EFBIG;
612-
goto err_big;
613-
}
608+
if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32)
609+
return ERR_PTR(-EFBIG);
614610

615611
/* Find the last address before DF start address, that is AC end */
616612
if (fw_addr == 0xf000)
@@ -623,12 +619,8 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
623619

624620
/* DF end address is the last address in the firmware blob */
625621
*df_end = fw_addr + fw_len;
626-
*buf = fw_buf;
627-
return 0;
628622

629-
err_big:
630-
kvfree(fw_buf);
631-
return error;
623+
return_ptr(fw_buf);
632624
}
633625

634626
/* Switch mode between Application and BootLoader */
@@ -691,7 +683,7 @@ static int ili251x_firmware_busy(struct i2c_client *client)
691683
return 0;
692684
}
693685

694-
static int ili251x_firmware_write_to_ic(struct device *dev, u8 *fwbuf,
686+
static int ili251x_firmware_write_to_ic(struct device *dev, const u8 *fwbuf,
695687
u16 start, u16 end, u8 dataflash)
696688
{
697689
struct i2c_client *client = to_i2c_client(dev);
@@ -776,47 +768,17 @@ static void ili210x_hardware_reset(struct gpio_desc *reset_gpio)
776768
msleep(300);
777769
}
778770

779-
static ssize_t ili210x_firmware_update_store(struct device *dev,
780-
struct device_attribute *attr,
781-
const char *buf, size_t count)
771+
static int ili210x_do_firmware_update(struct ili210x *priv,
772+
const u8 *fwbuf, u16 ac_end, u16 df_end)
782773
{
783-
struct i2c_client *client = to_i2c_client(dev);
784-
struct ili210x *priv = i2c_get_clientdata(client);
785-
const char *fwname = ILI251X_FW_FILENAME;
786-
const struct firmware *fw;
787-
u16 ac_end, df_end;
788-
u8 *fwbuf;
774+
struct i2c_client *client = priv->client;
775+
struct device *dev = &client->dev;
789776
int error;
790777
int i;
791778

792-
error = request_ihex_firmware(&fw, fwname, dev);
793-
if (error) {
794-
dev_err(dev, "Failed to request firmware %s, error=%d\n",
795-
fwname, error);
796-
return error;
797-
}
798-
799-
error = ili251x_firmware_to_buffer(fw, &fwbuf, &ac_end, &df_end);
800-
release_firmware(fw);
801-
if (error)
802-
return error;
803-
804-
/*
805-
* Disable touchscreen IRQ, so that we would not get spurious touch
806-
* interrupt during firmware update, and so that the IRQ handler won't
807-
* trigger and interfere with the firmware update. There is no bit in
808-
* the touch controller to disable the IRQs during update, so we have
809-
* to do it this way here.
810-
*/
811-
disable_irq(client->irq);
812-
813-
dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
814-
815-
ili210x_hardware_reset(priv->reset_gpio);
816-
817779
error = ili251x_firmware_reset(client);
818780
if (error)
819-
goto exit;
781+
return error;
820782

821783
/* This may not succeed on first try, so re-try a few times. */
822784
for (i = 0; i < 5; i++) {
@@ -826,7 +788,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
826788
}
827789

828790
if (error)
829-
goto exit;
791+
return error;
830792

831793
dev_dbg(dev, "IC is now in BootLoader mode\n");
832794

@@ -835,15 +797,15 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
835797
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0xf000, df_end, 1);
836798
if (error) {
837799
dev_err(dev, "DF firmware update failed, error=%d\n", error);
838-
goto exit;
800+
return error;
839801
}
840802

841803
dev_dbg(dev, "DataFlash firmware written\n");
842804

843805
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0x2000, ac_end, 0);
844806
if (error) {
845807
dev_err(dev, "AC firmware update failed, error=%d\n", error);
846-
goto exit;
808+
return error;
847809
}
848810

849811
dev_dbg(dev, "Application firmware written\n");
@@ -856,22 +818,63 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
856818
}
857819

858820
if (error)
859-
goto exit;
821+
return error;
860822

861823
dev_dbg(dev, "IC is now in Application mode\n");
862824

863825
error = ili251x_firmware_update_cached_state(dev);
864826
if (error)
865-
goto exit;
827+
return error;
866828

867-
error = count;
829+
return 0;
830+
}
831+
832+
static ssize_t ili210x_firmware_update_store(struct device *dev,
833+
struct device_attribute *attr,
834+
const char *buf, size_t count)
835+
{
836+
struct i2c_client *client = to_i2c_client(dev);
837+
struct ili210x *priv = i2c_get_clientdata(client);
838+
const char *fwname = ILI251X_FW_FILENAME;
839+
u16 ac_end, df_end;
840+
int error;
841+
842+
const struct firmware *fw __free(firmware) = NULL;
843+
error = request_ihex_firmware(&fw, fwname, dev);
844+
if (error) {
845+
dev_err(dev, "Failed to request firmware %s, error=%d\n",
846+
fwname, error);
847+
return error;
848+
}
849+
850+
const u8* fwbuf __free(kvfree) =
851+
ili251x_firmware_to_buffer(fw, &ac_end, &df_end);
852+
error = PTR_ERR_OR_ZERO(fwbuf);
853+
if (error)
854+
return error;
855+
856+
/*
857+
* Disable touchscreen IRQ, so that we would not get spurious touch
858+
* interrupt during firmware update, and so that the IRQ handler won't
859+
* trigger and interfere with the firmware update. There is no bit in
860+
* the touch controller to disable the IRQs during update, so we have
861+
* to do it this way here.
862+
*/
863+
disable_irq(client->irq);
864+
865+
dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
866+
867+
ili210x_hardware_reset(priv->reset_gpio);
868+
869+
error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end);
868870

869-
exit:
870871
ili210x_hardware_reset(priv->reset_gpio);
872+
871873
dev_dbg(dev, "Firmware update ended, error=%i\n", error);
874+
872875
enable_irq(client->irq);
873-
kvfree(fwbuf);
874-
return error;
876+
877+
return error ?: count;
875878
}
876879

877880
static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store);

0 commit comments

Comments
 (0)