drivers/hid/hid-picolcd_fb.c

Source file repositories/reference/linux-study-clean/drivers/hid/hid-picolcd_fb.c

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-picolcd_fb.c
Extension
.c
Size
15906 bytes
Lines
580
Domain
Driver Families
Bucket
drivers/hid
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (tdata[i] != vdata[i]) {
			changed = 1;
			vdata[i] = tdata[i];
		}
	return changed;
}

void picolcd_fb_refresh(struct picolcd_data *data)
{
	if (data->fb_info)
		schedule_delayed_work(&data->fb_info->deferred_work, 0);
}

/* Reconfigure LCD display */
int picolcd_fb_reset(struct picolcd_data *data, int clear)
{
	struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
	struct picolcd_fb_data *fbdata = data->fb_info->par;
	int i, j;
	unsigned long flags;
	static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };

	if (!report || report->maxfield != 1)
		return -ENODEV;

	spin_lock_irqsave(&data->lock, flags);
	for (i = 0; i < 4; i++) {
		for (j = 0; j < report->field[0]->maxusage; j++)
			if (j == 0)
				hid_set_field(report->field[0], j, i << 2);
			else if (j < sizeof(mapcmd))
				hid_set_field(report->field[0], j, mapcmd[j]);
			else
				hid_set_field(report->field[0], j, 0);
		hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
	}
	spin_unlock_irqrestore(&data->lock, flags);

	if (clear) {
		memset(fbdata->vbitmap, 0, PICOLCDFB_SIZE);
		memset(fbdata->bitmap, 0, PICOLCDFB_SIZE*fbdata->bpp);
	}
	fbdata->force = 1;

	/* schedule first output of framebuffer */
	if (fbdata->ready)
		schedule_delayed_work(&data->fb_info->deferred_work, 0);
	else
		fbdata->ready = 1;

	return 0;
}

/* Update fb_vbitmap from the screen_buffer and send changed tiles to device */
static void picolcd_fb_update(struct fb_info *info)
{
	int chip, tile, n;
	unsigned long flags;
	struct picolcd_fb_data *fbdata = info->par;
	struct picolcd_data *data;

	mutex_lock(&info->lock);

	spin_lock_irqsave(&fbdata->lock, flags);
	if (!fbdata->ready && fbdata->picolcd)
		picolcd_fb_reset(fbdata->picolcd, 0);
	spin_unlock_irqrestore(&fbdata->lock, flags);

	/*
	 * Translate the framebuffer into the format needed by the PicoLCD.
	 * See display layout above.
	 * Do this one tile after the other and push those tiles that changed.
	 *
	 * Wait for our IO to complete as otherwise we might flood the queue!
	 */
	n = 0;
	for (chip = 0; chip < 4; chip++)
		for (tile = 0; tile < 8; tile++) {
			if (!fbdata->force && !picolcd_fb_update_tile(
					fbdata->vbitmap, fbdata->bitmap,
					fbdata->bpp, chip, tile))
				continue;
			n += 2;
			if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
				spin_lock_irqsave(&fbdata->lock, flags);
				data = fbdata->picolcd;
				spin_unlock_irqrestore(&fbdata->lock, flags);
				mutex_unlock(&info->lock);
				if (!data)
					return;

Annotation

Implementation Notes