Việc làm firmware cho một thiết bị làm việc duy nhất như cái webcam chạy Linux về cơ bản không có gì đặc biệt khác gì làm một hệ điều hành như Ubuntu. Chúng ta chỉ làm đơn giản hơn khi làm firmware nhúng vì:
1. Firmware chỉ chạy trên một thiết bị có một cấu hình cố định (ở đây là Raspberry Pi 0 gắn thêm một chiếc sensor ở cổng CSI), chứ không phải lo chạy trên tất cả các máy tính.
2. Chúng ta chỉ phải chạy một (vài) chương trình cố định để làm một việc cố định thay vì phải chạy tất cả các tổ hợp chương trình mà người dùng muốn chạy.
Có một số vấn đề mà nếu như chỉ chạy OS trên máy tính thì bạn sẽ hơi ngạc nhiên:
- Chẳng lẽ Linux mà cũng là lựa chọn đúng cho thiết bị nhúng à? Câu hỏi ngược lại là tại sao không dùng Linux. Có rất nhiều thiết bị nhúng không chạy Linux, nhưng không có nghĩa Linux là lựa chọn sai.
- Linux là hệ điều hành đa nhiệm trong khi đó chúng ta chỉ làm một việc duy nhất, vậy có lãng phí không? Thực ra việc swap các chương trình trên CPU để chạy đa nhiệm không làm cho chương trình chạy chậm hơn bao nhiêu. Điểm có lợi lớn là các máy tính chạy Linux rất dễ lập trình và test. Chúng ta không mất công viết driver (trong trường hợp này tất cả driver đã được viết trước trong nhân Linux rồi). Test chương trình trên Linux dễ hơn trên rất nhiều nền tảng nhúng khác.
- Linux khởi động mất một phút trên máy tính của tôi, làm sao mà khởi động cái webcam nhanh được? Việc máy tính của bạn khởi động chậm không có nghĩa là cái gì chạy Linux khởi động cũng chậm.
Nhưng bàn luận lo lắng nhiều nữa, chúng ta hãy cùng bắt tay vào tìm hiểu làm cách nào để build firmware này từ đầu.
Trước tiên, để xác định là chúng ta sẽ mất bao công để làm được một firmware như thế này. Chúng ta phải viết chương trình gì, làm những việc gì?
Lưu ý về lập trình, hầu như chúng ta không phải viết gì. Tất cả các chương trình tên là uvc-gadget đã được viết sẵn (http://www.davidhunt.ie/raspberry-pi-zero-with-pi-camera-as-usb-webcam/), và nếu ai đang chạy Raspbian có thể chạy ngay chương trình này rồi. Ta chỉ phải đóng gói chương trình này lại thành một firmware hoàn chỉnh.

Đóng gói uvc-gadget

Từ chương trình của uvc-gadget -- nói một cách tổng quát, chúng ta có hai cách để "nhúng"  và đóng gói chương trình webcam này vào thành một firmware hoàn chỉnh. Tức là khởi động máy, chạy uvc-gadget, hết. Đây là một việc đơn giản. Nhưng thực hiện như thế nào? Chúng ta có ít ra hai cách:
1. Bắt đầu tỉa từ trên ngọn xuống: Lấy Raspbian, tùy biến: cài đặt uvc-gadget, bỏ các gói phần mềm ta không cần, cho uvc-gadget vào thư mục startup bằng cách này hay cách khác rồi đóng gói lại ship đi.
2. Bắt đầu từ cái gốc lên: Lấy gốc nhân Linux, thêm uvc-gadget và các thành phần cần thiết, rồi đóng gói lại ship đi.
Ở đây, cách 1 có điểm lợi là không phải tìm hiểu nhiều, nhanh gọn, mọi thứ đã chạy sẵn chỉ phải bỏ đi cái không cần. Điều này là cách tiếp cận của mình khi làm crankshaft. Có người như Jeff Gerling cũng làm với firmware webcam raspberry của anh ấy (https://www.youtube.com/watch?v=8fcbP7lEdzY) theo cách này.
Tuy nhiên vấn đề khi ta làm theo cách tỉa từ trên ngọn xuống, thì việc tối ưu hóa, làm cho firmware nhỏ gọn chạy nhanh, không phụ thuộc vào các thành phần khác là rất rất khó. Hơn nữa, khi làm từ trên ngọn xuống thì chúng ta vẫn coi chiếc Raspberry Pi là một chiếc máy tính để bàn. Việc này làm cho chúng ta học được không nhiều.
Khi làm từ dưới gốc lên, chúng ta sẽ có nhiều cơ hội hiểu được cách hệ thống khởi động, thiết lập, làm được mọi việc rõ ràng hơn và nhiều lợi ích khác mình sẽ tiếp tục khai thác vào các phần sau.

Linux và các tiến trình

Trước tiên, hãy xem chiếc máy tính Linux của chúng ta thật sự "chạy chương trình" như thế nào. Thường khi ta dùng máy tính Windows hay Linux, chúng ta có một khái niệm mơ hồ về việc chạy chương trình bằng cách bấm đúp chuột lên một biểu tượng hay đánh lệnh trên dòng lệnh. Khi chương trình (cho ví dụ trình duyệt Chromium) chạy, thì nó có một process ("tiến trình") tên là Chromium trên máy tính. Khi bạn mở Task Manager lên thì sẽ thấy một danh sách bằng vai phải lứa như thế này có tiến trình Chromium ở đó (ảnh chụp KSysMonitor - Task Manager của KDE):

Nhưng thực ra các chương trình không bằng vai phải lứa như thế, chương trình nào cũng có nguồn gốc và được "gọi" từ một chương trình tổ tiên của nó. Việc này cũng như hệ thống thư mục của Linux vậy -- cái gì cũng bắt đầu từ /. Ở trên Linux, bạn có thể theo dõi cây phả hệ của tất cả các chương trình bằng lệnh pstree, bạn có thể gọi bằng
pstree | less
Bạn sẽ thấy một cái cây như thế này:

Chúng ta sẽ thấy thực ra Chromium không tự nhiên chạy mà do "plasmashell" gọi nó chạy. Đó là do plasmashell (Plasma Desktop - KDE, tương đương với explorer shell trên Windows, explorer.exe) thấy bạn bấm đúp lên icon Chromium. Trên Linux, quá trình này được làm do một process gọi một hàm hệ thống là fork() và sau đó process mới này gọi hàm exec().
Trở về nữa, ta sẽ thấy tổ tiên của Plasma là một chương trình có tên là systemd, nhưng đặc biệt systemd không có tổ tiên trên nó. Vậy Systemd, anh là ai?

Systemd và Init system

Khi nhân hệ điều hành như Linux khởi động hết tất cả phần cứng đến gần xong, nhân Linux sẽ gọi một chương trình ở /sbin/init để nhân Linux chuyển sang chế độ "user mode" tức là cho các chương trình phục vụ cho người dùng. Chương trình /sbin/init này sẽ tiếp tục đi fork() các process khác hữu ích cho người dùng (như process cho phép bạn login, process vẽ lên màn hình giao điện đồ họa). Nhân Linux gắn cho process này ID là số 1, rồi theo dõi process này. Process này không bao giờ chết, khi nó chết hoặc thoát ra máy tính của bạn sẽ khởi động lại.
Trên các hệ thống Linux tân kỳ, chương trình /sbin/init này gọi là systemd. Nó có nhiệm vụ đi gọi tất cả các chương trình hữu ích khác của hệ thống. Nó là ông tổ, chương trình quan trọng nhất của hệ thống.
Kỳ sau, chúng ta sẽ cùng học viết một chương trình init đơn giản nhất để máy raspberry pi làm một việc, và sẽ tiếp tục thọc sâu vào việc khởi động chương trình bằng Systemd.

Tham khảo

Các bạn thấy thích thú có thể đọc thêm bằng cách vào các đường dẫn hoặc Google các từ khóa sau:

- The init Process - Linux Device Drivers, Second Edition https://www.oreilly.com/library/view/linux-device-drivers/0596000081/ch16s03.html
- man fork 2 và fork (system call)
- man execve 2
Thủ thuật: Trên linux bạn có thể đánh man execve 2 chứ không cần phải vào web.