static void siox_poll()

in siox-core.c [128:276]


static void siox_poll(struct siox_master *smaster)
{
	struct siox_device *sdevice;
	size_t i = smaster->setbuf_len;
	unsigned int devno = 0;
	int unsync_error = 0;

	smaster->last_poll = jiffies;

	/*
	 * The counter bits change in each second cycle, the watchdog bit
	 * toggles each time.
	 * The counter bits hold values from [0, 6]. 7 would be possible
	 * theoretically but the protocol designer considered that a bad idea
	 * for reasons unknown today. (Maybe that's because then the status read
	 * back has only zeros in the counter bits then which might be confused
	 * with a stuck-at-0 error. But for the same reason (with s/0/1/) 0
	 * could be skipped.)
	 */
	if (++smaster->status > 0x0d)
		smaster->status = 0;

	memset(smaster->buf, 0, smaster->setbuf_len);

	/* prepare data pushed out to devices in buf[0..setbuf_len) */
	list_for_each_entry(sdevice, &smaster->devices, node) {
		struct siox_driver *sdriver =
			to_siox_driver(sdevice->dev.driver);
		sdevice->status_written = smaster->status;

		i -= sdevice->inbytes;

		/*
		 * If the device or a previous one is unsynced, don't pet the
		 * watchdog. This is done to ensure that the device is kept in
		 * reset when something is wrong.
		 */
		if (!siox_device_synced(sdevice))
			unsync_error = 1;

		if (sdriver && !unsync_error)
			sdriver->set_data(sdevice, sdevice->status_written,
					  &smaster->buf[i + 1]);
		else
			/*
			 * Don't trigger watchdog if there is no driver or a
			 * sync problem
			 */
			sdevice->status_written &= ~SIOX_STATUS_WDG;

		smaster->buf[i] = sdevice->status_written;

		trace_siox_set_data(smaster, sdevice, devno, i);

		devno++;
	}

	smaster->pushpull(smaster, smaster->setbuf_len, smaster->buf,
			  smaster->getbuf_len,
			  smaster->buf + smaster->setbuf_len);

	unsync_error = 0;

	/* interpret data pulled in from devices in buf[setbuf_len..] */
	devno = 0;
	i = smaster->setbuf_len;
	list_for_each_entry(sdevice, &smaster->devices, node) {
		struct siox_driver *sdriver =
			to_siox_driver(sdevice->dev.driver);
		u8 status = smaster->buf[i + sdevice->outbytes - 1];
		u8 status_clean;
		u8 prev_status_clean = sdevice->status_read_clean;
		bool synced = true;
		bool connected = true;

		if (!siox_device_synced(sdevice))
			unsync_error = 1;

		/*
		 * If the watchdog bit wasn't toggled in this cycle, report the
		 * watchdog as active to give a consistent view for drivers and
		 * sysfs consumers.
		 */
		if (!sdriver || unsync_error)
			status &= ~SIOX_STATUS_WDG;

		status_clean =
			siox_status_clean(status,
					  sdevice->status_written_lastcycle);

		/* Check counter and type bits */
		if (siox_device_counter_error(sdevice, status_clean) ||
		    siox_device_type_error(sdevice, status_clean)) {
			bool prev_error;

			synced = false;

			/* only report a new error if the last cycle was ok */
			prev_error =
				siox_device_counter_error(sdevice,
							  prev_status_clean) ||
				siox_device_type_error(sdevice,
						       prev_status_clean);

			if (!prev_error) {
				sdevice->status_errors++;
				sysfs_notify_dirent(sdevice->status_errors_kn);
			}
		}

		/* If the device is unsynced report the watchdog as active */
		if (!synced) {
			status &= ~SIOX_STATUS_WDG;
			status_clean &= ~SIOX_STATUS_WDG;
		}

		if (siox_device_wdg_error(sdevice, status_clean))
			connected = false;

		/* The watchdog state changed just now */
		if ((status_clean ^ prev_status_clean) & SIOX_STATUS_WDG) {
			sysfs_notify_dirent(sdevice->watchdog_kn);

			if (siox_device_wdg_error(sdevice, status_clean)) {
				struct kernfs_node *wd_errs =
					sdevice->watchdog_errors_kn;

				sdevice->watchdog_errors++;
				sysfs_notify_dirent(wd_errs);
			}
		}

		if (connected != sdevice->connected)
			sysfs_notify_dirent(sdevice->connected_kn);

		sdevice->status_read_clean = status_clean;
		sdevice->status_written_lastcycle = sdevice->status_written;
		sdevice->connected = connected;

		trace_siox_get_data(smaster, sdevice, devno, status_clean, i);

		/* only give data read to driver if the device is connected */
		if (sdriver && connected)
			sdriver->get_data(sdevice, &smaster->buf[i]);

		devno++;
		i += sdevice->outbytes;
	}
}