El controlador del dispositivo en sí funciona simplemente escribiendo al FIFO de UART y a los registros de control.
La razón principal por la que normalmente querría usar el controlador en lugar de escribir directamente en el UART es porque el controlador le da una capa de abstracción. Le permite tratar esa UART como otras UART, e incluso a veces como cualquier otro archivo. No necesita saber qué bit es el bit de datos preparados y qué registros de divisor son para el UART que estaba utilizando, ya que el controlador hace que todos los UART se vean casi iguales. Además, el controlador normalmente le brinda un gran búfer administrado en la parte superior de los FIFO y maneja todas las interrupciones, lo que requiere escribir algún código especializado en Linux.
Dicho esto, hay ocasiones en que escribir directamente en el UART puede darle control que no está disponible a través del controlador. Aquí hay un proyecto donde omito el controlador de dispositivo Linux en una Raspberry PI y voy directamente a la UART para poder generar señales para un WS2812B ...
enlace
Esto no sería posible hacerlo a través del controlador porque depende de algunas peculiaridades de la UART específica, junto con algunas transiciones de estado de las que no hay forma de hacer que el controlador funcione de manera confiable en el orden correcto.
En los casos en que decida escribir directamente en el UART, probablemente sea una buena idea desactivar el controlador para evitar conflictos. Por ejemplo, si está intentando leer bytes fuera de FIFO a través de su programa de espacio de usuario, es probable que el controlador también esté leyendo bytes y gane porque se dispara por interrupciones. De manera similar, puede cambiar algún registro directamente mientras el controlador asume que el registro se mantendrá configurado para lo que lo haya inicializado (o viceversa).