[c/linux] Obsługa USB

0

Witam,

Muszę obsłużyć to nieszczęsne USB na linuksie. Kiedyś ćwiczyłem się z pisaniem sterowników - znam "szkielet" i jak kompilować. Obsłużyć muszę komunikację miedzy kompem a ARMem. Jakby się dało to zrobiłbym na rs232 lecz te piękne gniazda w laptopach zniknęły, a przelotkami bawić się nie będę. Nie mam doświadczenia w komunikacji USB i mam kilka wątpliwości. Potrzebuje już w głównym programie(daemonie), zdarzenie które się wykona po odebraniu paczki z mikrokontrolera - wywoływanie funkcji która zwraca dane z odebranej paczki trochę będzie niezręczne(przy komunikacji z drivera), tak jak w przypadku windowsowskich bibliotek.... Mogę być w błędzie gdyż tego typu oprogramowanie z wykorzystaniem USB będzie moim pierwszym. Nie chcę emulować rs232, tylko tak jak to "profesionalne" urządzenia na USB które mają własne sterowniki.
Iiii mianowicie mam pytanie... Jak dobrać się do USB w driverze i jak przesyłać dane do głównego programu? Przez sockety jak w przypadku programu gpsd który odczytuje pozycje z GPSa na USB, a "główny" program się łączy i posiada zdarzenie odbioru? Nie wiem jak się do tego zabrać [???]
Paczka danych to 32bitowa wartość wysyłana z częstotliwością ok 10-0,1kHz.
Proszę o pomoc :-(

0

zaciekawil mnie ten temat rowniez, i zdziwil ze nie znalazles materialow, wiec puscilem w ruch wiadomo co, z wiadomo jakim zapytaniem.. piata odpowiedz na liscie wynikow brzmiala
http://www.linuxjournal.com/article/4786
IMHO, direct hit?

0

@quetzalcoatl: ten artykul jest z 2001, czyli czas jajek 2.4, wiec mozliwe, ze jest nie aktualny, ale usb sam do tej pory nie ruszalem, wiec nie wiem do konca

Proponuje zernac do tej ksiazki, jesli chodzi o pisanie driverow jest ona najbardziej aktualna.
http://lwn.net/Kernel/LDD3/

Ten link tez sie przyda
http://www.gnugeneration.com/mirrors/kernel-api/book1.html

W miare normalnie sa jeszcze napisane sterowniki zydas, wiec tez mozesz zerknac w kod. Patrzylem wlasnie i powiem szczerze, ze nie problem sie polapac o co chodzi.
Tu wkleilem kod zd1210.
http://pastebin.com/nSwMgpNX

Co do samego wyszukiwania urzadzen usb to zrodelka lsusb mysle, ze beda sie nadawaly.</url>

0

Dzięki za odpowiedź.
Znalazłem prosty przykład http://www.linuxjournal.com/article/7353 i do niego się odwołuję.
Coś takiego wyskrobałem, trochę zmniejszona wersja powyższego modułu, usiłuję tylko połączyć się z urządzeniem:

#lsusb
Bus 005 Device 034: ID 03eb:6124 Atmel Corp. at91sam SAMBA bootloader
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>

#include <net/iw_handler.h>
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/firmware.h>

#define DRIVER_AUTHOR "moja osobistosc"
#define DRIVER_DESC "USB My Driver"

#define VENDOR_ID 0x03eb
#define PRODUCT_ID 0x6124

//static struct usb_device_id usbdeviceid = {USB_DEVICE(0x03eb, 0x6124)};
static struct usb_device_id id_table [] = {
	{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
	{ },
};
MODULE_DEVICE_TABLE (usb, id_table);

static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
	struct usb_device *udev = interface_to_usbdev(interface);
	struct usb_led *dev = NULL;
	int retval = -ENOMEM;

/*	dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL);
	if (dev == NULL) {
		dev_err(&interface->dev, "Out of memory\n");
		goto error;
	}
	memset (dev, 0x00, sizeof (*dev));

	dev->udev = usb_get_dev(udev);

	usb_set_intfdata (interface, dev);

	device_create_file(&interface->dev, &dev_attr_blue);
	device_create_file(&interface->dev, &dev_attr_red);
	device_create_file(&interface->dev, &dev_attr_green);

	dev_info(&interface->dev, "USB LED device now attached\n");
	return 0;

error:
	kfree(dev);*/
	return retval;
}

static void led_disconnect(struct usb_interface *interface)
{
	struct usb_led *dev;
/*
	dev = usb_get_intfdata (interface);
	usb_set_intfdata (interface, NULL);

	device_remove_file(&interface->dev, &dev_attr_blue);
	device_remove_file(&interface->dev, &dev_attr_red);
	device_remove_file(&interface->dev, &dev_attr_green);

	usb_put_dev(dev->udev);

	kfree(dev);

	dev_info(&interface->dev, "USB LED now disconnected\n");*/
}


static struct usb_driver led_driver = {
	//.owner =	THIS_MODULE,
	.name =		"usbled",
	.probe =	led_probe,
	.disconnect =	led_disconnect,
	.id_table =	id_table,
};

int init_module()
{
unsigned int retval;
retval = usb_register(&led_driver);
//err("Helloo!!!");
if (retval)
        err("usb_register failed. "
            "Error number %d", retval);

    return 0;
}

void cleanup_module()
{

}
obj-m    := main.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)

default:
	make -C $(KDIR) SUBDIRS=$(PWD) modules

Przy tej linijce mam błąd

.owner =        THIS_MODULE,
error: unknown field 'owner' specified in initializer

Bez niej wszystko się kompiluje, ale przy próbie załadowania:

main: Unknown symbol usb_register_driver

Coś zgubiłem w makefile?
kernel 2.6.32.8 slackware 12.2

0

Widac stary jakis przyklad, zerknij u siebie jak wyglada struktura usb_driver w /lib/modules/$(uname -r)/build/include/linux/usb.h, bo u mnie na 2.6.32-22, wyglada tak:

struct usb_driver {
	const char *name;

	int (*probe) (struct usb_interface *intf,
		      const struct usb_device_id *id);

	void (*disconnect) (struct usb_interface *intf);

	int (*ioctl) (struct usb_interface *intf, unsigned int code,
			void *buf);

	int (*suspend) (struct usb_interface *intf, pm_message_t message);
	int (*resume) (struct usb_interface *intf);
	int (*reset_resume)(struct usb_interface *intf);

	int (*pre_reset)(struct usb_interface *intf);
	int (*post_reset)(struct usb_interface *intf);

	const struct usb_device_id *id_table;

	struct usb_dynids dynids;
	struct usbdrv_wrap drvwrap;
	unsigned int no_dynamic_id:1;
	unsigned int supports_autosuspend:1;
	unsigned int soft_unbind:1;
};

owner tam nie ma, wiec mozliwe ze u Ciebie tez nie ma i stad ten blad ;)

0

Jeszcze masz blad taki, ze teraz inaczej sie moduly inicjalizuje, powinnienes na koncu dac takie dwie funkcje z linux/init.h:

module_init(nazwa_funkcja_pierwszej);
module_exit(nazwa_funkcji_ostatniej);

oraz do tych wlasnych funkcji inicjalizujacej i zamykajacej zwyklo sie dodawac

__init
__exit

czyli tak powinno byc

static int __init module_laduj(void)
{
   printk(KERN_INFO "hip hip hurra :D\n");
   return 0;
}

static void __exit module_czesc(void)
{
   printk("narazie ;p\n");
}

module_init(module_laduj);
module_exit(module_czesc);
0

Jeszcze dwie wazne rzeczy na przyszlosc:

  1. jak chcesz przesylac i pobierac dane z przestrzeni uzytkownika to korzystaj z put_user() i get_user
  2. pamietaj o liczniku uzyc modulu, zebys przypadkiem nie zakonczyl go gdy ktos z niego korzysta, poniewaz bedzie siedzial w systemie, az do restartu, dwie pomocne funkcje
try_module_get(THIS_MODULE);          // zwieksza o jeden ten licznik
module_put(THIS_MODULE);               // zmniejsza

jak sie sprawdza juz nie pamietam ;p

0

Sorki za posta pod postem kolejnego, ale nie doczytalem, ze sie kompiluje bez tego.

Blad, ktory masz przy ladowaniu wynika z tego, ze nie uzyles funkcji usb_register_driver tylko usb_register, ktora byc moze jest przestarzala, zreszta jasno masz napisane w komunikacie o bledzie.

Co do makefile to jest w porzadku.

0

Dzięki, ale to później popracuję nad modułem, teraz chcę zobaczyć oznaki życia połączenia przez USB.
Coś nie tak z tym usb_register.

static int __init module_laduj(void)
{
  int retval;
   printk(KERN_INFO "hip hip hurra :D\n");
    retval = usb_register_driver(&led_driver, THIS_MODULE, "He???");
    if (retval)
        err("usb_register failed. "
            "Error number %d", retval);

    return 0;
}

static void __exit module_czesc(void)
{
//   usb_deregister(&led_driver);
   printk("narazie ;p\n");
}

module_init(module_laduj);
module_exit(module_czesc);

Wszystko się kompiluje tylko dalej ten błąd...

main: Unknown symbol usb_register_driver
0

na razie sie dowiedzialem, ze moze byc usb_register() jednak. Sam zaczalem kombinowac z tym, poniewaz ten sam problem mam z troche przerobionym moim modulem. Jak znajde rozwiazanie to napisze.

0

Coś jest z czymś nie tak. Nawet taki gotowiec co się elegancko kompiluje wywala to samo:
http://vaioz31.blogspot.com/2009/04/3g-support-qualcomm-gobi-chipset-step1.html

0

łłłłoooo modprobe usbserial [green]

0

U mnie nic to nie dalo. Wrzuc jak mozesz wynik lsmod u siebie, moze jeszcze czegos mi brakuje.

0

USB to jak Usilne Sterowanie Bąkiem.
Poddaje sie ;-(

0

Teraz sie strasznie zdenerwowalem na ten system. Komunikat o bledzie moim zdaniem kompletnie nie wlasciwy, z tego co pamietam byl inny w tej sprawie jasno mowiacy ocb.
Mianowicie chodzi o taka glupote, zeby dopisac.

MODULE_LICENSE("GPL");

Bez tego nie idzie w ogole.

0

Znaczy licencja moze byc inna, ale trzeba napisac jaka ;)

0

YYyyy dodałem

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

działa... rozumiem Cię, ale nadal nie wiem o co chodzi.... znaczy wiem.... nie... i o to kur** tyle krzyku?...

0

No wlasnie o to. Pamietam, ze jeszcze na 2.6.18 tylko wyskakiwal warning przy kompilacji modulu o brak umieszczenia informacji o licencji, a teraz jak widac taki cyrk sie dzieje.

0

Wykrywa mi driver urządzenie, zostało mi teraz obsłużyć "transfer".
W mikrokontrolerze mam napisany program, który odbiera dane i Od razu je odsyła.
Chciałem się posłużyć funkcją usb_control_msg ale w manualach jest słabo opisana, po źródłach innych programów nie mogę załapać o co chodzi z tymi argumentami.... Jak wysyłać odbierać dane? I jak zrobić przerwanie/zdarzenie które wykona się po wysłaniu do kompa danych?
Idę dalej studiować to USB, jeśli dla kogoś nie będzie problemu z pomocą co do powyższych pytań to bardzo proszę, bo trochę się już gubię :-|

0

Wyklepałem coś takiego, niestety operacja się nie powiodła.

static int usb_probe(struct usb_interface *interface, const struct usb_device_id *id){
  int retval = -ENOMEM;
  char * buffer;
  struct usb_device * udev = interface_to_usbdev(interface);
  struct usb_dat *dev = NULL;
  dev = kmalloc(sizeof(struct usb_dat), GFP_KERNEL);
  if(!dev){
    dev_err(&interface->dev, "Out of memory\n");
    return retval;
  }
  memset(dev, 0x00, sizeof(*dev));
  dev->udev = usb_get_dev(udev);
  usb_set_intfdata(interface, dev);
//  device_create_file(&interface->dev, &dev_attr_data);
  dev_info(&interface->dev, "USB device now attached\n");
// #define USB_DIR_OUT			0		/* to device */
// #define USB_DIR_IN			0x80		/* to host */
  buffer = kmalloc(1024, GFP_ATOMIC);
  strcpy(buffer, "OK");
  retval = usb_control_msg(udev,
                           usb_sndctrlpipe(udev, 0),
                           0,
                           USB_DIR_OUT | USB_TYPE_VENDOR,// | USB_RECIP_DEVICE, //USB_DIR_OUT  //USB_DIR_IN,
                           7,
                           9,
                           buffer,	
                           3,
                           10 * HZ);

  printk("usb_control_msg: %d\n", retval);
  kfree(buffer);
  return 0;
}
usb_test 4-1:1.0: USB device now attached
usb_control_msg: -32
usb_test 4-1:1.1: USB device now attached
usb_control_msg: -32

Źle dobieram się do usb_control_msg? Czy coś z prockiem mam nie tak....? Usb_probe i disconnect działają poprawnie(tzn wywoływanie).

0

Tu masz przyklady jak sie uzywa tej funkcji:
http://www.codase.com/search/call?name=usb_control_msg

a blad masz konkretnie taki:
"USB error: error sending control message: Broken pipe"

Natomiast jak juz wczesniej pisalem nie bawilem sie usb, wiec nic raczej dalej nie doradze, ale google bedzie pewnie wiedzialo jak sobie z tym bledem poradzic i te przyklady moze pomoga.

tu jeszcze cos jest
http://cboard.cprogramming.com/cplusplus-programming/123294-cplusplus-libusb-usb_control_msg-problem.html

0

Chyba się udało :-)

  strcpy(buffer, "OK");

  retval = usb_control_msg(udev,
                           usb_sndctrlpipe(udev, 1),
                           0,
                           USB_DIR_OUT  | USB_TYPE_VENDOR,
                           0,
                           0,
                           buffer,	
                           3,
                           1 * HZ);
  printk("usb_control_msg: %d\n", retval);
  buffer[0]='x';
  retval = usb_control_msg(udev,
                           usb_rcvctrlpipe(udev, 2),
                           0,
                           USB_DIR_IN  | USB_TYPE_VENDOR,
                           0,
                           0,
                           buffer,	
                           3,
                           1 * HZ);
  printk("usb_control_msg: %d\n\n", retval);
  printk("CHAR: %s\n", buffer);
  kfree(buffer);
  return 0;
usb_test 5-2:1.0: USB device now attached
usb_control_msg: 3
usb_control_msg: 3

CHAR: OK
usb_test 5-2:1.1: USB device now attached
usb_control_msg: 3
usb_control_msg: 3

CHAR: OK

Przy wysyłaniu usb_sndctrlpipe(udev, 1) a odbiorze usb_rcvctrlpipe(udev, 2). Wartości 1 i 2 wymyśliłem.... Jest to (czyli drugi argument) jakiś endpoint, może ktoś po ludzku wyjaśnić o co z tym pipami i endpointami chodzi? I czemu tworzą się 2 "dostępy" do usb?

root@slack:/# ls -l /sys/bus/usb/drivers/usb_test/
total 0
lrwxrwxrwx 1 root root    0 2010-05-17 17:20 5-2:1.0 -> ../../../../devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2:1.0/
lrwxrwxrwx 1 root root    0 2010-05-17 17:20 5-2:1.1 -> ../../../../devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2:1.1/
0

Te pipy sa to potoki sluzace przede wszystkim do komunikacji miedzyprocesorowej. W Twoim przypadku zostaja utworzone dwa lacza, z czego jedno jest do zapisu do urzadzenia, a drugie do odczytu. Natomiast jesli chodzi o endpointy to nie wiem ale na ten temat jest sporo napisane w 13 rozdziale tej ksiazki co link dalem w 3 poscie.

0

Aaaa to te pipy ;-) A co do książki to się powoli drukuje ;-P
Mam jeszcze pytanie odnośnie przesyłania danych między driverem a programem/daemonem... Czy przesyłać dane za pomocą tych "device_create_file"(czyli /sys/bus/usb/drivers/gdzies_tam)? Stworzyć coś w /dev/? w /proc/? Tyle możliwości że nie wiem co lepsze, a w driverach to ja lewy jestem [green]
Tymczasowo mam utworzone przez device_create_file i bawię się catem i echem przesyłając dane do procka, fajnie, szybko poszło - dzięki za pomoc w uruchomieniu transmisji [browar]
Interesują mnie jeszcze nazwy przydzielone do "idVendor".

Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Gdzieś to się rejestruje? - żeby urządzenie wyszło na świat i miało własny numer z nazwą bez konfliktów?
Na armie mam taką tabelkę:

const char devDescriptor[] = {
	/* Device descriptor */
	0x12,   // bLength
	0x01,   // bDescriptorType
	0x10,   // bcdUSBL
	0x01,   //
	0x02,   // bDeviceClass:    CDC class code
	0x00,   // bDeviceSubclass: CDC class sub code
	0x00,   // bDeviceProtocol: CDC Device protocol
	0x08,   // bMaxPacketSize0
	0xEB,   // idVendorL
	0x03,   //
	0x24,   // idProductL
	0x61,   //
	0x10,   // bcdDeviceL
	0x01,   //
	0x00,   // iManufacturer    // 0x01
	0x00,   // iProduct
	0x00,   // SerialNumber
	0x01    // bNumConfigs
};

Wymyślać Vendora raczej nie mogę bo jeszcze trafie na istniejący i drivery zgłupieją.

1 użytkowników online, w tym zalogowanych: 0, gości: 1